# Climate Orders quickstart Enable your customers to buy carbon removal using the Climate API with your payments integration. # Climate Orders quickstart Enable your customers to buy carbon removal using the [Climate Orders API](https://docs.stripe.com/api/climate/order.md) with your payments integration. ### Install the Stripe Node library Install the package and import it in your code. Alternatively, if you’re starting from scratch and need a package.json file, download the project files using the Download link in the code editor. Install the library: Or download the stripe-node library source code directly [from GitHub](https://github.com/stripe/stripe-node). ### Install the Stripe Ruby library Install the Stripe ruby gem and require it in your code. Alternatively, if you’re starting from scratch and need a Gemfile, download the project files using the link in the code editor. Install the gem: Add this line to your Gemfile: Or download the stripe-ruby gem source code directly [from GitHub](https://github.com/stripe/stripe-ruby). ### Install the Stripe Java library Add the dependency to your build and import the library. Alternatively, if you’re starting from scratch and need a sample pom.xml file (for Maven), download the project files using the link in the code editor. Add the following dependency to your POM and replace {VERSION} with the version number you want to use. Add the dependency to your build.gradle file and replace {VERSION} with the version number you want to use. Download the JAR directly [from GitHub](https://github.com/stripe/stripe-java/releases/latest). ### Install the Stripe Python package Install the Stripe package and import it in your code. Alternatively, if you’re starting from scratch and need a requirements.txt file, download the project files using the link in the code editor. Install the package via pip: Download the stripe-python library source code directly [from GitHub](https://github.com/stripe/stripe-python/releases). ### Install the Stripe PHP library Install the library with composer and initialize with your secret API key. Alternatively, if you’re starting from scratch and need a composer.json file, download the files using the link in the code editor. Install the library: Or download the stripe-php library source code directly [from GitHub](https://github.com/stripe/stripe-php). ### Set up your server Add the dependency to your build and import the library. Alternatively, if you’re starting from scratch and need a go.mod file, download the project files using the link in the code editor. Make sure to initialize with Go Modules: Or download the stripe-go module source code directly [from GitHub](https://github.com/stripe/stripe-go). ### Install the Stripe.net library Install the package with .NET or NuGet. Alternatively, if you’re starting from scratch, download the files which contains a configured .csproj file. Install the library: Install the library: Or download the Stripe.net library source code directly [from GitHub](https://github.com/stripe/stripe-dotnet). ### Install the Stripe libraries Install the packages and import them in your code. Alternatively, if you’re starting from scratch and need a `package.json` file, download the project files using the link in the code editor. Install the libraries: ### Create an endpoint to handle the request Add an endpoint on your server that creates a [Checkout Session](https://docs.stripe.com/api/checkout/sessions.md). The Checkout Session controls what your customer sees on the payment page. ### Calculate the order amount Use [Climate Products](https://docs.stripe.com/api/climate/product.md) to fetch the latest price and calculate the total order amount. ### Create a customer Look up a [Customer](https://docs.stripe.com/api/customers.md) in your database, or create a new `Customer` to represent who you’re invoicing. ### Create an empty invoice Make sure to pass the [product.id](https://docs.stripe.com/api/climate/product/object.md#climate_product_object-id) in `metadata` and set the [collection_method](https://docs.stripe.com/api/invoices/object.md#invoice_object-collection_method) attribute to `send_invoice`. For Stripe to mark an invoice as past due, you must add the [days_until_due](https://docs.stripe.com/api/invoices/create.md#create_invoice-days_until_due) parameter. When you send an invoice, Stripe emails the invoice to the customer with payment instructions. For more invoice customization options, see [Invoices](https://docs.stripe.com/api/invoices.md). ### Create an invoice item Create an invoice item by passing in the `customer.id`, `invoice.id`, and the order’s `amount_total` and `currency`. ### Send the invoice Send the invoice to the email address associated with the customer and redirect to a success page. As soon as you send an invoice, Stripe finalizes it. Many jurisdictions consider finalized invoices a legal document making certain fields unalterable. If you send invoices that have already been paid, there’s no reference to the payment in the email. With any finalized invoice, you can either download and send a [PDF](https://docs.stripe.com/api/invoices/object.md#invoice_object-invoice_pdf) or [link](https://docs.stripe.com/api/invoices/object.md#invoice_object-hosted_invoice_url) to the associated [Hosted Invoice Page](https://docs.stripe.com/invoicing/hosted-invoice-page.md). ### Create a Checkout Session Create a `Checkout Session` to collect payment from your customers. ### Configure the Checkout Session Make sure to pass the [product.id](https://docs.stripe.com/api/climate/product/object.md#climate_product_object-id) in `metadata`. For more Checkout Session customization options, see [Checkout](https://docs.stripe.com/api/checkout/sessions.md). ### Supply success and cancel URLs Specify URLs for success and cancel pages—make sure they’re publicly accessible so Stripe can redirect customers to them. You can also handle both the success and canceled states with the same URL. ### Redirect to Checkout After creating the session, redirect your customer to the URL for the Checkout page returned in the response. ### Create a top-up This funds your order using your account’s linked bank account, passing [product.id](https://docs.stripe.com/api/climate/product/object.md#climate_product_object-id) in `metadata`. Make sure that your bank account allows for debits from Stripe, and has the balance available to cover your order. ### Create a carbon removal order A [Climate Order](https://docs.stripe.com/api/climate/order.md) reserves the carbon removal and tracks it through delivery. The total amount is deducted from your [Stripe balance](https://docs.stripe.com/api/balance.md). For production code, move creating the Climate Order to an offline process and handle duplicate events. See [Best practices for using webhooks](https://docs.stripe.com/webhooks.md#best-practices) for more details. ### Create a carbon removal order When the user pays their invoice, create the [Climate Order](https://docs.stripe.com/api/climate/order.md). The total amount is deducted from your [Stripe balance](https://docs.stripe.com/api/balance.md). For production code, move creating the Climate Order to an offline process and handle duplicate events. See [Best practices for using webhooks](https://docs.stripe.com/webhooks.md#best-practices) for more details. ### Create a carbon removal order When the user completes their payment using Checkout, create the [Climate Order](https://docs.stripe.com/api/climate/order.md). The total amount is deducted from your [Stripe balance](https://docs.stripe.com/api/balance.md). For production code, move creating the Climate Order to an offline process and handle duplicate events. See [Best practices for using webhooks](https://docs.stripe.com/webhooks.md#best-practices) for more details. ### Create a carbon removal order When the top-up is successful, create the [Climate Order](https://docs.stripe.com/api/climate/order.md). The total amount is deducted from your [Stripe balance](https://docs.stripe.com/api/balance.md). For production code, move creating the Climate Order to an offline process and handle duplicate events. See [Best practices for using webhooks](https://docs.stripe.com/webhooks.md#best-practices) for more details. ### Add an order preview page Add a page to preview the carbon removal you’re selling and collect an email from your customer. Display your marketing assets here and clearly explain the expected delivery date and applicable guarantees for the product. ### Add an order preview page Add a page to preview the carbon removal you’re selling. Display your marketing assets here and clearly explain the expected delivery date and applicable guarantees for the product. ### Add an order button Add a button to place an order and send the invoice. ### Add an order button Add a button to place an order. When your customer clicks this button, they’re redirected to the Stripe-hosted payment form. ### Handle redirect back from Checkout Show a message to your customer when they’re redirected back to your page. ### Add an order page Create a page in your application to place an order. ### Download the asset kit Use [the asset kit](https://stripe-images.s3.amazonaws.com/content-store/climate/APIAssetKit.zip) to introduce your customers to carbon removal products. ### Set your environment variables Add your publishable and secret keys to a `.env` file. Next.js automatically loads them into your application as [environment variables](https://nextjs.org/docs/basic-features/environment-variables). Also include a webhook secret, which you can create in the [Dashboard](https://dashboard.stripe.com/webhooks) or with the [Stripe CLI](https://docs.stripe.com/stripe-cli.md). ### Run the application Start your app with `npm run dev` and navigate to [http://localhost:3000](http://localhost:3000). ### Try it out Click **checkout** to redirect to the Checkout page. Use any of these test cards to simulate a payment. | Scenario | Card Number | | ------------------------------- | ---------------- | | Payment succeeds | 4242424242424242 | | Payment requires authentication | 4000002500003155 | | Payment is declined | 4000000000009995 | ### Try it out Click **place order** to send a test invoice. Use any of these test cards to simulate paying the invoice. | Scenario | Card Number | | ------------------------------- | ---------------- | | Payment succeeds | 4242424242424242 | | Payment requires authentication | 4000002500003155 | | Payment is declined | 4000000000009995 | ### Verify your carbon removal order View the `Climate Order` in the [Stripe Dashboard](https://dashboard.stripe.com/climate/orders) to confirm that it’s been created successfully. ```jsx import React from "react"; export default function App() { const [message, setMessage] = React.useState(""); React.useEffect(() => { // Check to see if this is a redirect back from the server const query = new URLSearchParams(window.location.search); if (query.get("success")) { setMessage("Order placed!"); } if (query.get("canceled")) { setMessage("Order canceled."); } }, []); return (
{message ? (

{message}

) : (

Frontier's 2027 offtake portfolio

$550.00/ton
)}
); } ``` ```jsx import React from "react"; export default function App() { return (

Frontier's 2027 offtake portfolio

$550.00/ton
); } ``` ```javascript const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY); export default async function handler(req, res) { if (req.method === 'POST') { const currency = 'usd'; const {data: products} = await stripe.climate.products.list(); // Select which carbon removal product you want to order const climateProduct = products.find((p) => p.id === 'climsku_frontier_offtake_portfolio_2027'); // Calculate the total amount based on the number of tons const unit_amount = 1.0 * climateProduct.current_prices_per_metric_ton[currency].amount_total; // Look up a product in your database or create a new one const product = await stripe.products.create({ name: climateProduct.name, }); // Create Checkout Sessions from body params. const session = await stripe.checkout.sessions.create({ line_items: [ { price_data: { unit_amount, currency, product: product.id, }, quantity: 1, }, ], mode: 'payment', metadata: { climate_product: climateProduct.id }, success_url: `${req.headers.origin}?success=true`, cancel_url: `${req.headers.origin}?canceled=true`, }); res.redirect(303, session.url); } else { res.setHeader('Allow', 'POST'); res.status(405).end('Method Not Allowed'); } } ``` ```javascript const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY); export default async function handler(req, res) { if (req.method === 'POST') { const currency = 'usd'; const {data: products} = await stripe.climate.products.list(); // Select which carbon removal product you want to order const climateProduct = products.find((p) => p.id === 'climsku_frontier_offtake_portfolio_2027'); // Calculate the total amount based on the number of tons const unit_amount = 1.0 * climateProduct.current_prices_per_metric_ton[currency].amount_total; // Look up a customer in your database or create a new one const customer = await stripe.customers.create({email: 'TODO@example.com'}) // Create an Invoice const invoice = await stripe.invoices.create({ customer: customer.id, collection_method: 'send_invoice', days_until_due: 1, metadata: { climate_product: climateProduct.id }, }); // Look up a product in your database or create a new one const product = await stripe.products.create({ name: climateProduct.name, }); // Create an Invoice Item with the Price, and Customer you want to charge await stripe.invoiceItems.create({ customer: customer.id, invoice: invoice.id, price_data: { unit_amount, currency, product: product.id, }, }); // Send the Invoice await stripe.invoices.sendInvoice(invoice.id) res.redirect(303, req.headers.origin + '?success=true'); } else { res.setHeader('Allow', 'POST'); res.status(405).end('Method Not Allowed'); } } ``` ```javascript const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY); export default async function handler(req, res) { if (req.method === 'POST') { const currency = 'usd'; const {data: products} = await stripe.climate.products.list(); // Select which product you want to order const product = products.find((product) => product.id === 'climsku_frontier_offtake_portfolio_2027'); // Calculate the total amount based on the number of tons const amount = 1.0 * product.current_prices_per_metric_ton[currency].amount_total; // Create a top-up await stripe.topups.create({ amount, currency, metadata: { climate_product: product.id }, }); res.redirect(303, req.headers.origin + '?success=true'); } else { res.setHeader('Allow', 'POST'); res.status(405).end('Method Not Allowed'); } } ``` ```javascript const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY); export default async function handler(req, res) { if (req.method === 'POST') { const order = await stripe.climate.orders.create({ metric_tons: '1.0', product: 'climsku_frontier_offtake_portfolio_2027', }); res.redirect(303, req.headers.origin + '?success=true'); } else { res.setHeader('Allow', 'POST'); res.status(405).end('Method Not Allowed'); } } ``` ```javascript import Stripe from 'stripe'; import { buffer } from 'micro'; import Cors from 'micro-cors'; const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET; // Stripe requires the raw body to construct the event. export const config = { api: { bodyParser: false, }, }; const cors = Cors({ allowMethods: ['POST', 'HEAD'], }); async function webhookHandler(req, res) { if (req.method === 'POST') { const buf = await buffer(req); const signature = req.headers['stripe-signature']; let event; try { event = stripe.webhooks.constructEvent( buf.toString(), signature, webhookSecret ); } catch (err) { // On error, log and return the error message. console.log(`❌ Error message: ${err.message}`); res.status(400).send(`Webhook Error: ${err.message}`); return; } // Successfully constructed event. console.log('✅ Success:', event.id); switch (event.type) { case 'invoice.paid': { const invoice = event.data.object; if (invoice.metadata.climate_product) { await stripe.climate.orders.create({ amount: invoice.total, currency: invoice.currency, product: invoice.metadata.climate_product, }); } break; } case 'checkout.session.completed': { const session = event.data.object; if (session.metadata.climate_product) { await stripe.climate.orders.create({ amount: session.amount_total, currency: session.currency, product: session.metadata.climate_product, }); } break; } case 'topup.succeeded': { const topup = event.data.object; if (topup.metadata.climate_product) { await stripe.climate.orders.create({ amount: topup.amount, currency: topup.currency, product: topup.metadata.climate_product, }); } break; } default: { console.warn(`Unhandled event type: ${event.type}`); break; } } // Return a response to acknowledge receipt of the event. res.json({ received: true }); } else { res.setHeader('Allow', 'POST'); res.status(405).end('Method Not Allowed'); } }; export default cors(webhookHandler); ``` ```bash # https://dashboard.stripe.com/apikeys STRIPE_SECRET_KEY=<> # Set this environment variable to support webhooks — https://stripe.com/docs/webhooks#verify-events STRIPE_WEBHOOK_SECRET=whsec_12345 ``` ```bash \# Stripe keys # https://dashboard.stripe.com/apikeys STRIPE_SECRET_KEY=sk_12345 # Set this environment variable to support webhooks — https://stripe.com/docs/webhooks#verify-events STRIPE_WEBHOOK_SECRET=whsec_12345 ``` ```bash .DS_Store .vscode # Node files node_modules/ # Next.js .next .vercel .env .env*.local next-env.d.ts ``` ```json { "name": "stripe-sample", "version": "0.0.0", "description": "Full-stack example using Next.js", "scripts": { "dev": "next", "build": "next build", "start": "next start" }, "dependencies": { "@stripe/react-stripe-js": "^2.4.0", "@stripe/stripe-js": "^2.4.0", "micro": "^10.0.0", "micro-cors": "0.1.1", "next": "^13.4.0", "react": "^18.2.0", "react-dom": "^18.2.0", "stripe": "^14.14.0" } } ```