How to add a custom field to invoices generated by subscriptions

80 views
Skip to first unread message

Brazos Donaho

unread,
Dec 15, 2023, 10:30:45 PM12/15/23
to Stripe API Discussion
In the Stripe dashboard, a new subscription can be created for a customer and under the heading of 'Subscription settings' and 'Advanced' custom invoice fields can be defined.  These will then appear at the top of all invoices generated for the subscription.

I am trying to create the same functionality using the API to create a new subscription.  There does not appear to be a place to apply custom fields directly on the subscription, and the invoice exposed by the subscription is 'Finalized' and not able to be changed.  

I have tried responding to web hooks, etc and I can't find a way to alter the invoice.

Thanks for any suggestions.

Remi J.

unread,
Dec 15, 2023, 10:35:20 PM12/15/23
to api-d...@lists.stripe.com
Hello,

At the moment we don't support this feature in the API and it is only available in the Dashboard. A potential workaround is to set this on the Customer object itself using the `invoice_settings[custom_fields]` parameter [1]. It will automatically be set on all Invoices under that Customer and would apply to all Subscriptions too.

We do want to add the ability to control this per Subscription in the API in the future but haven't yet started working on this.

Hope this helps as a workaround!
Best,
Remi


--
To unsubscribe from this group and stop receiving emails from it, send an email to api-discuss...@lists.stripe.com.

Brazos Donaho

unread,
Dec 15, 2023, 10:44:10 PM12/15/23
to Stripe API Discussion, re...@stripe.com
Thank you for the fast reply.  We will have multiple subscriptions  per customer so customer level won't work.  

Thanks.

Remi J.

unread,
Dec 15, 2023, 11:01:55 PM12/15/23
to Stripe API Discussion
Unfortunately we don't really have a cleaner solution today in the API.

Alternatively, you can update the `custom_fields` of an Invoice when you get the `invoice.created` Event delivered to your WebhookEndpoint. The main gotcha is that you can't edit finalized Invoices and the first Invoice of a Subscription is finalized automatically on creation. Potential workarounds are
1. Set the default one on the Customer before the Subscription creation and unset those after so that the first Invoice of the Subscription inherits those but not future ones.
2. Use a SubscriptionSchedule on creation instead as the first Invoice of those is not automatically finalized which gives you time to edit the Invoice.

I'll raise this feedback internally again though as I would really like to get to parity with our Dashboard UI in this case.

Brazos Donaho

unread,
Dec 16, 2023, 1:18:40 PM12/16/23
to Stripe API Discussion, re...@stripe.com
Thank you.  I will try creating a SubscriptionSchedule, updating the invoice, then releasing the schedule.   Hopefully this workflow will do the trick.
Thanks

Brazos Donaho

unread,
Dec 17, 2023, 5:32:35 AM12/17/23
to Stripe API Discussion, re...@stripe.com
A little ugly, but works:

const minutes = 5;
const subscriptionSchedule = await stripe.subscriptionSchedules.create({
customer: stripe_customer_id,
start_date: 'now',
end_behavior: 'release',
phases: [
{
items: [
{
price: stripe_price_id
}
],
end_date: (Math.floor(Date.now()/1000)) + (minutes*60)
},
]
});

const scheduleSubscription = await stripe.subscriptions.retrieve(subscriptionSchedule.subscription);

const updatedInvoice = await stripe.invoices.update(
scheduleSubscription.latest_invoice,
{
custom_fields: [{name: 'Project', value: 'Project 42'}],
});

// Now release the SubscriptionSchedule
const releasedSubscriptionSchedule = await stripe.subscriptionSchedules.release(subscriptionSchedule.id);

const releasedSubscription = await stripe.subscriptions.retrieve(releasedSubscriptionSchedule.released_subscription);
const releasedInvoice = await stripe.invoices.retrieve(releasedSubscription.latest_invoice);
const finalizedInvoice = await stripe.invoices.finalizeInvoice(releasedInvoice.id);
const finalizedPaymentIntent = await stripe.paymentIntents.retrieve(finalizedInvoice.payment_intent);

// Use this clientSecret for customer payment form
const clientSecret = finalizedPaymentIntent.client_secret;

Reply all
Reply to author
Forward
0 new messages