Hosted invoice page

A VINR-hosted page where customers pay invoices.

View as MarkdownInstall skills

Every finalized invoice gets a secure, VINR-hosted page where your customer can review line items, pay with any supported method, download a PDF receipt, and update their default payment method. You don't build or host anything — VINR renders it, handles SCA, and emits events as the customer acts.

What the page doesAsk

The hosted invoice page is the customer-facing surface of an invoice. It is the default collection experience for both one-off invoices you send and the recurring invoices a subscription generates.

CapabilityDetail
Pay nowCharges the amount due using a card or stored method; handles SCA / 3DS inline.
Download PDFA finalized, branded invoice document for the customer's records.
Update payment methodSaves a new default method on the customer, reused for future cycles.
Status awarenessShows paid, past_due, or void and disables payment when no longer collectible.

The page is branded with the logo, colors, and support details from your branding settings, so it looks like your product, not ours.

When the URL existsAsk

A page URL is only present once the invoice is finalized — drafts have no payable surface. The link lives on the invoice as hosted_invoice_url and the PDF as invoice_pdf.

For subscription invoices, VINR finalizes automatically about an hour after the draft is created (or immediately on the first cycle). For invoices you create by hand, call vinr.invoices.finalize(...) to lock the invoice and mint the URL.

Retrieve the hosted page URLAsk

Finalize an invoice and read its hosted URL, then deliver that link however you like — VINR's own email, your transactional mail, or an in-app banner.

import { Vinr } from '@vinr/sdk';
const vinr = new Vinr({ secretKey: process.env.VINR_SECRET_KEY });

// Draft -> finalized; only finalized invoices have a hosted page.
const invoice = await vinr.invoices.finalize('inv_4Qp1Z8kR2');

console.log(invoice.hosted_invoice_url);
// https://pay.vinr.com/i/inv_4Qp1Z8kR2/9f3c...
console.log(invoice.invoice_pdf);
// https://pay.vinr.com/i/inv_4Qp1Z8kR2/9f3c.../pdf

If you'd rather have VINR email the page for you, set collection_method: 'send_invoice' when creating the invoice and call vinr.invoices.send(invoice.id) — VINR sends a branded email containing the same link.

curl https://api.vinr.com/v1/invoices/inv_4Qp1Z8kR2/send \
  -H "X-Api-Key: $VINR_SECRET_KEY" \
  -X POST

What the customer sees and doesAsk

The customer lands on the hosted page over HTTPS. The URL embeds a signed token, so no login is required — but the token is scoped to that single invoice and expires once the invoice is paid or voided.

Review and pay

They see line items, tax, discounts, and the amount due, then pay with a card or a previously stored method. VINR runs any required SCA challenge in-page.

Land on confirmation

On success the page shows a receipt and a PDF download. VINR marks the invoice paid and the underlying payment completed.

Resulting eventsAsk

Listen for these on your webhook endpoint (verify with vinr.webhooks.verify(payload, signature)). Fulfil access on invoice.paid, never on a client-side redirect.

EventFires when
invoice.finalizedThe page URL becomes available.
payment.completedThe customer's payment succeeds on the page.
invoice.paidThe invoice is fully settled — your fulfilment trigger.
invoice.payment_failedA payment attempt is declined; feeds dunning.
export async function POST(req: Request) {
  const payload = await req.text();
  const signature = req.headers.get('x-vinr-signature')!;
  const event = vinr.webhooks.verify(payload, signature);

  if (event.type === 'invoice.paid') {
    const invoice = event.data; // amount_paid in minor units, e.g. 2000 = €20.00
    await grantAccess(invoice.customer);
  }
  return new Response('ok', { status: 200 });
}

Edge casesAsk

Next stepsAsk

Was this page helpful?
Edit on GitHub

Last updated on

On this page