Skip to content

Integrate Commerce Into My App

Use the Proyecta SDK to create customers, start checkouts, gate features, and cancel subscriptions from your app code.

Once you’ve connected Stripe and created a product, you wire commerce into your app via the proyecta.commerce SDK resource. The four most common operations are: create a customer, start a checkout, check feature access, and cancel a subscription.

import Proyecta from '@proyecta-ai/sdk';
const proyecta = new Proyecta({ apiKey: process.env.PROYECTA_API_KEY });

A customer is the billable entity in your app — usually a user, org, or project. Create one as soon as the corresponding entity is created in your database, then store the returned id so you can reference the customer in checkouts and access checks.

const customer = await proyecta.commerce.customers.create({
email: 'alice@example.com',
name: 'Alice Liddell',
// optional custom id, must start with 'cus_'
});
await db.users.update({ id: userId, proyectaCustomerId: customer.id });

You can also pass a billing address (line1, line2, city, state, postal_code, country) at creation or via customers.update().

commerce.checkout() creates a Stripe-hosted checkout session and returns a URL to redirect the customer to. After payment, Stripe redirects the customer to your success_url.

const { url } = await proyecta.commerce.checkout({
customer_id: customer.id,
line_items: [{ variant_id: 'var_pro_monthly', quantity: 1 }],
success_url: 'https://myapp.com/welcome',
cancel_url: 'https://myapp.com/pricing',
promotion_code: 'LAUNCH20', // optional
});
return Response.redirect(url);

Multiple line_items are supported. For subscriptions, quantity represents seat count.

If the customer is already subscribed and you call checkout() again, the response is an update action instead of a redirect — Proyecta swaps the variant in place. You can override timing/proration:

await proyecta.commerce.checkout({
customer_id,
line_items: [{ variant_id: 'var_business_monthly' }],
success_url: 'https://myapp.com/account',
charge_timing: 'immediate', // or 'end_of_period'
proration_behavior: 'prorate', // or 'none', 'full_difference'
plan_downgrade_behavior: 'end_of_period',
});

Before letting a customer use a premium feature, call commerce.check() to verify they have access:

const { has_access } = await proyecta.commerce.check({
customer_id: customer.id,
resource_id: 'feat_pro_features',
});
if (!has_access) {
return Response.json({ error: 'Upgrade required' }, { status: 402 });
}

This is the recommended way to gate premium content. See Products & Features for the feature/entitlement model.

await proyecta.commerce.cancel({
customer_id: customer.id,
subscription_id: 'sub_123',
cancellation_timing: 'at_billing_period_end', // or 'immediate'
});

By default, the customer keeps access until the end of the billing period.

Stripe provides a hosted billing portal where customers can update payment methods, view invoices, and manage their own subscriptions. Generate the URL and redirect:

const { url } = await proyecta.commerce.customers.billingPortal(customer.id, {
return_url: 'https://myapp.com/account',
});
return Response.redirect(url);

You don’t need to write this by hand. Common prompts:

  • "Create a Proyecta customer when a user signs up. Store the proyecta_customer_id on the user record."
  • "Build a /pricing page that shows my Proyecta products and starts a checkout when a button is clicked."
  • "Gate the /admin route — only allow users whose Proyecta customer has access to feat_admin."
  • "Add a 'Manage billing' button on the account page that opens the Proyecta customer billing portal."
  • "When a user clicks Cancel Subscription, call proyecta.commerce.cancel with at_billing_period_end."