cURL
curl --request POST 'https://api.integrateledger.com/v1/billing/import' \
-H "Authorization: Bearer $LEDGER_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"customerId":"user_123","stripeSubscriptionId":"sub_123","planId":"pro"}'import ledger from "integrateledger";
const client = new ledger({ apiKey: process.env.LEDGER_API_KEY ?? "" });
await client.importSubscription({ customerId: "user_123", stripeSubscriptionId: "sub_123", planId: "pro" });import os
from integrateledger import ledger
client = ledger(api_key=os.environ["LEDGER_API_KEY"])
client.import_subscription(customer_id="user_123", stripe_subscription_id="sub_123", plan_id="pro"){
"subscriptionId": 123,
"planId": "<string>",
"status": "active",
"currentPeriodStart": "2023-11-07T05:31:56Z",
"currentPeriodEnd": "2023-11-07T05:31:56Z",
"cancelAtPeriodEnd": true,
"grantedCredits": 1,
"imported": true
}{
"error": "<string>",
"reason": "<string>",
"message": "<string>"
}{
"error": "<string>",
"reason": "<string>",
"message": "<string>"
}{
"error": "<string>",
"reason": "<string>",
"message": "<string>"
}{
"error": "<string>",
"reason": "<string>",
"message": "<string>"
}{
"error": "payload_too_large"
}{
"error": "rate_limited"
}{
"error": "internal_error",
"request_id": "<string>"
}{
"error": "<string>",
"reason": "<string>",
"message": "<string>"
}Billing
Import a Stripe subscription
Move a customer’s existing Stripe subscription onto a Ledger plan, with no charge.
POST
/
v1
/
billing
/
import
cURL
curl --request POST 'https://api.integrateledger.com/v1/billing/import' \
-H "Authorization: Bearer $LEDGER_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"customerId":"user_123","stripeSubscriptionId":"sub_123","planId":"pro"}'import ledger from "integrateledger";
const client = new ledger({ apiKey: process.env.LEDGER_API_KEY ?? "" });
await client.importSubscription({ customerId: "user_123", stripeSubscriptionId: "sub_123", planId: "pro" });import os
from integrateledger import ledger
client = ledger(api_key=os.environ["LEDGER_API_KEY"])
client.import_subscription(customer_id="user_123", stripe_subscription_id="sub_123", plan_id="pro"){
"subscriptionId": 123,
"planId": "<string>",
"status": "active",
"currentPeriodStart": "2023-11-07T05:31:56Z",
"currentPeriodEnd": "2023-11-07T05:31:56Z",
"cancelAtPeriodEnd": true,
"grantedCredits": 1,
"imported": true
}{
"error": "<string>",
"reason": "<string>",
"message": "<string>"
}{
"error": "<string>",
"reason": "<string>",
"message": "<string>"
}{
"error": "<string>",
"reason": "<string>",
"message": "<string>"
}{
"error": "<string>",
"reason": "<string>",
"message": "<string>"
}{
"error": "payload_too_large"
}{
"error": "rate_limited"
}{
"error": "internal_error",
"request_id": "<string>"
}{
"error": "<string>",
"reason": "<string>",
"message": "<string>"
}Imports a subscription you already bill in Stripe onto a paid Ledger plan. Link the customer’s Stripe customer first with Link a Stripe customer. The plan’s monthly price must equal the subscription’s. The full walkthrough is Migrate from Stripe Billing.
Ledger moves the subscription’s item to the plan’s own Stripe Price, with no proration: nothing is charged now, and the renewal date and amount stay the same. It then grants the plan’s credits for Stripe’s current period and treats the subscription like one it sold: each paid renewal grants the next period’s credits, and upgrades and cancellations work through Ledger. Send
startingBalance to carry over the credits the customer has left this period; it defaults to the plan’s monthly credits.
An active subscription, one set to cancel at the period end, and a trialing one can be imported; a trial becomes the plan’s first period. Ledger refuses, without changing anything:
400 subscription_past_due,subscription_incomplete,subscription_ended,subscription_not_billableorlatest_invoice_unpaid: collect or void the open invoice in Stripe first, or don’t import an ended subscription.400 unsupported_subscriptionwith areason: something Ledger can’t bill yet:multiple_items,quantity,price_mismatch,not_monthly,metered_price,send_invoice,discount,schedule,pending_update,pause_collection,billing_thresholds,pending_invoice_itemsorcustomer_balance.409 stripe_customer_not_linkedorstripe_customer_mismatch: link the subscription’s own Stripe customer first.409 multiple_subscriptions: the Stripe customer has another subscription that isn’t canceled.409 subscription_exists: the customer already has a paid plan or a pending Checkout. An active free plan is replaced by the import.
message: the subscription is already on the plan’s Price, with nothing charged, but not imported. Fix what it names and import again.
Importing the same subscription onto the same plan again returns it with imported: false and changes nothing; onto another plan, it returns 409 subscription_already_imported. Like attach, the import needs a healthy signed webhook endpoint (502 stripe_not_configured or stripe_webhook_unhealthy), because the credits for every later renewal arrive by webhook. It works in Live and doesn’t need Ledger’s live-charge approval, since it starts no charge. The key needs the billing:write permission.Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Body
application/json
The Ledger customer. Link its Stripe customer first with POST /v1/customers/stripe-customer.
Required string length:
1 - 255The customer's existing subscription in your Stripe account.
Maximum string length:
255The paid Ledger plan it becomes. Its monthly price must equal the subscription's.
Required string length:
1 - 255The plan credits the customer has left this period, to carry over their usage. Defaults to the plan's monthly credits.
Required range:
x >= 0Response
The subscription is the customer's Ledger plan
Available options:
active The subscription ends at the period end in Stripe; Ledger ends the plan then.
Credits granted for the current period.
Required range:
x >= 0False when the subscription had already been imported.