---
url: /stripe-payment-records.md
---
# Record Maytes payments in Stripe

A Maytes order doesn't appear in your Stripe Dashboard, because Stripe takes no payment for it. After you capture, add the order to Stripe as an invoice paid outside Stripe. It then shows in your Stripe Dashboard, and your customer can download a Stripe receipt.

::: tip No money moves through Stripe
You're still paid through [Maytes settlements](/portal).
:::

## What you'll see in Stripe

* **Invoices:** a **Paid** invoice for the order.
* **Payments:** a payment shown as **Paid out of band**, plus a canceled **Payment for Invoice**.
* **Receipt:** **Paid with: Split with Maytes** in its header.

Stripe creates the **Payment for Invoice** when you finalize the invoice, then cancels it when you mark the invoice paid. It moves no money, and you can't avoid it.

Each customer also gets a Maytes receipt for their own share.

## What you need

Do this from your server, right after [capture](/capture-and-status#capture-the-full-amount) returns `status: "captured"`. The examples use these values:

| In the examples | Where it comes from |
|---|---|
| `amount` | The capture response's `amount`, in minor units: `4500` is AUD 45.00 |
| `currency` | The capture response's `currency`, in lowercase: `AUD` becomes `aud` |
| `orderId` | The capture response's `merchant_order_id`, or your own order number if you didn't send one |
| `checkoutUuid` | The capture response's `checkout_uuid`, kept in the invoice's metadata so you can match it to the Maytes order |

Python and Ruby use `order_id` and `checkout_uuid`. Your Stripe secret key is read from `STRIPE_SECRET_KEY`.

## 1. Create the customer

Create a Stripe customer, or use one you already have. A receipt needs the customer's email address.

::: code-group

```ts [TypeScript]
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

const customer = await stripe.customers.create({
  name: 'Customer Name',
  email: 'customer@example.com',
});
```

```python [Python]
import os
from stripe import StripeClient

stripe = StripeClient(os.environ["STRIPE_SECRET_KEY"])

customer = stripe.v1.customers.create({
    "name": "Customer Name",
    "email": "customer@example.com",
})
```

```php [PHP]
$stripe = new \Stripe\StripeClient(getenv('STRIPE_SECRET_KEY'));

$customer = $stripe->customers->create([
    'name'  => 'Customer Name',
    'email' => 'customer@example.com',
]);
```

```go [Go]
sc := stripe.NewClient(os.Getenv("STRIPE_SECRET_KEY"))

customer, err := sc.V1Customers.Create(ctx, &stripe.CustomerCreateParams{
	Name:  stripe.String("Customer Name"),
	Email: stripe.String("customer@example.com"),
})
if err != nil { /* handle */ }
```

```java [Java]
StripeClient stripe = new StripeClient(System.getenv("STRIPE_SECRET_KEY"));

Customer customer = stripe.v1().customers().create(
    CustomerCreateParams.builder()
        .setName("Customer Name")
        .setEmail("customer@example.com")
        .build());
```

```ruby [Ruby]
stripe = Stripe::StripeClient.new(ENV.fetch('STRIPE_SECRET_KEY'))

customer = stripe.v1.customers.create({
  name: 'Customer Name',
  email: 'customer@example.com',
})
```

```csharp [.NET]
var stripe = new StripeClient(Environment.GetEnvironmentVariable("STRIPE_SECRET_KEY"));

var customer = await stripe.V1.Customers.CreateAsync(new CustomerCreateOptions
{
    Name = "Customer Name",
    Email = "customer@example.com",
});
```

:::

## 2. Create the receipt

Stripe makes receipts from paid invoices. Create an invoice for the order, finalize it, then mark it as paid outside Stripe.

::: code-group

```ts [TypeScript]
const invoice = await stripe.invoices.create({
  customer: customer.id,
  currency,
  collection_method: 'send_invoice',
  days_until_due: 0,
  auto_advance: false,
  description: `Order ${orderId}`,
  custom_fields: [{ name: 'Paid with', value: 'Split with Maytes' }],
  metadata: { maytes_checkout_uuid: checkoutUuid },
});

await stripe.invoiceItems.create({
  customer: customer.id,
  invoice: invoice.id,
  amount,
  currency,
  description: `Order ${orderId}`,
});

await stripe.invoices.finalizeInvoice(invoice.id, { auto_advance: false });

await stripe.invoices.pay(invoice.id, { paid_out_of_band: true });
```

```python [Python]
invoice = stripe.v1.invoices.create({
    "customer": customer.id,
    "currency": currency,
    "collection_method": "send_invoice",
    "days_until_due": 0,
    "auto_advance": False,
    "description": f"Order {order_id}",
    "custom_fields": [{"name": "Paid with", "value": "Split with Maytes"}],
    "metadata": {"maytes_checkout_uuid": checkout_uuid},
})

stripe.v1.invoice_items.create({
    "customer": customer.id,
    "invoice": invoice.id,
    "amount": amount,
    "currency": currency,
    "description": f"Order {order_id}",
})

stripe.v1.invoices.finalize_invoice(invoice.id, {"auto_advance": False})

stripe.v1.invoices.pay(invoice.id, {"paid_out_of_band": True})
```

```php [PHP]
$invoice = $stripe->invoices->create([
    'customer'          => $customer->id,
    'currency'          => $currency,
    'collection_method' => 'send_invoice',
    'days_until_due'    => 0,
    'auto_advance'      => false,
    'description'       => "Order {$orderId}",
    'custom_fields'     => [['name' => 'Paid with', 'value' => 'Split with Maytes']],
    'metadata'          => ['maytes_checkout_uuid' => $checkoutUuid],
]);

$stripe->invoiceItems->create([
    'customer'    => $customer->id,
    'invoice'     => $invoice->id,
    'amount'      => $amount,
    'currency'    => $currency,
    'description' => "Order {$orderId}",
]);

$stripe->invoices->finalizeInvoice($invoice->id, ['auto_advance' => false]);

$stripe->invoices->pay($invoice->id, ['paid_out_of_band' => true]);
```

```go [Go]
invoice, err := sc.V1Invoices.Create(ctx, &stripe.InvoiceCreateParams{
	Customer:         stripe.String(customer.ID),
	Currency:         stripe.String(currency),
	CollectionMethod: stripe.String("send_invoice"),
	DaysUntilDue:     stripe.Int64(0),
	AutoAdvance:      stripe.Bool(false),
	Description:      stripe.String("Order " + orderId),
	CustomFields: []*stripe.InvoiceCreateCustomFieldParams{
		{Name: stripe.String("Paid with"), Value: stripe.String("Split with Maytes")},
	},
	Metadata: map[string]string{"maytes_checkout_uuid": checkoutUuid},
})
if err != nil { /* handle */ }

_, err = sc.V1InvoiceItems.Create(ctx, &stripe.InvoiceItemCreateParams{
	Customer:    stripe.String(customer.ID),
	Invoice:     stripe.String(invoice.ID),
	Amount:      stripe.Int64(amount),
	Currency:    stripe.String(currency),
	Description: stripe.String("Order " + orderId),
})
if err != nil { /* handle */ }

_, err = sc.V1Invoices.FinalizeInvoice(ctx, invoice.ID, &stripe.InvoiceFinalizeInvoiceParams{
	AutoAdvance: stripe.Bool(false),
})
if err != nil { /* handle */ }

_, err = sc.V1Invoices.Pay(ctx, invoice.ID, &stripe.InvoicePayParams{
	PaidOutOfBand: stripe.Bool(true),
})
if err != nil { /* handle */ }
```

```java [Java]
Invoice invoice = stripe.v1().invoices().create(
    InvoiceCreateParams.builder()
        .setCustomer(customer.getId())
        .setCurrency(currency)
        .setCollectionMethod(InvoiceCreateParams.CollectionMethod.SEND_INVOICE)
        .setDaysUntilDue(0L)
        .setAutoAdvance(false)
        .setDescription("Order " + orderId)
        .addCustomField(InvoiceCreateParams.CustomField.builder()
            .setName("Paid with")
            .setValue("Split with Maytes")
            .build())
        .putMetadata("maytes_checkout_uuid", checkoutUuid)
        .build());

stripe.v1().invoiceItems().create(
    InvoiceItemCreateParams.builder()
        .setCustomer(customer.getId())
        .setInvoice(invoice.getId())
        .setAmount(amount)
        .setCurrency(currency)
        .setDescription("Order " + orderId)
        .build());

stripe.v1().invoices().finalizeInvoice(invoice.getId(),
    InvoiceFinalizeInvoiceParams.builder().setAutoAdvance(false).build());

stripe.v1().invoices().pay(invoice.getId(),
    InvoicePayParams.builder().setPaidOutOfBand(true).build());
```

```ruby [Ruby]
invoice = stripe.v1.invoices.create({
  customer: customer.id,
  currency: currency,
  collection_method: 'send_invoice',
  days_until_due: 0,
  auto_advance: false,
  description: "Order #{order_id}",
  custom_fields: [{ name: 'Paid with', value: 'Split with Maytes' }],
  metadata: { maytes_checkout_uuid: checkout_uuid },
})

stripe.v1.invoice_items.create({
  customer: customer.id,
  invoice: invoice.id,
  amount: amount,
  currency: currency,
  description: "Order #{order_id}",
})

stripe.v1.invoices.finalize_invoice(invoice.id, { auto_advance: false })

stripe.v1.invoices.pay(invoice.id, { paid_out_of_band: true })
```

```csharp [.NET]
var invoice = await stripe.V1.Invoices.CreateAsync(new InvoiceCreateOptions
{
    Customer = customer.Id,
    Currency = currency,
    CollectionMethod = "send_invoice",
    DaysUntilDue = 0,
    AutoAdvance = false,
    Description = $"Order {orderId}",
    CustomFields = new List<InvoiceCustomFieldOptions>
    {
        new InvoiceCustomFieldOptions { Name = "Paid with", Value = "Split with Maytes" },
    },
    Metadata = new Dictionary<string, string> { ["maytes_checkout_uuid"] = checkoutUuid },
});

await stripe.V1.InvoiceItems.CreateAsync(new InvoiceItemCreateOptions
{
    Customer = customer.Id,
    Invoice = invoice.Id,
    Amount = amount,
    Currency = currency,
    Description = $"Order {orderId}",
});

await stripe.V1.Invoices.FinalizeInvoiceAsync(invoice.Id, new InvoiceFinalizeOptions
{
    AutoAdvance = false,
});

await stripe.V1.Invoices.PayAsync(invoice.Id, new InvoicePayOptions
{
    PaidOutOfBand = true,
});
```

:::

Save the invoice ID with your order for step 3.

`auto_advance: false` stops Stripe from sending or collecting the invoice. To list each line of your order on the receipt, add one invoice item per line. The items must add up to the captured amount.

## 3. Show the receipt

When your customer views their order, fetch the invoice and link to its `hosted_invoice_url`. That Stripe page lets them download the receipt.

::: code-group

```ts [TypeScript]
const { hosted_invoice_url } = await stripe.invoices.retrieve(invoiceId);
```

```python [Python]
hosted_invoice_url = stripe.v1.invoices.retrieve(invoice_id).hosted_invoice_url
```

```php [PHP]
$hostedInvoiceUrl = $stripe->invoices->retrieve($invoiceId)->hosted_invoice_url;
```

```go [Go]
inv, err := sc.V1Invoices.Retrieve(ctx, invoiceId, nil)
if err != nil { /* handle */ }
hostedInvoiceURL := inv.HostedInvoiceURL
```

```java [Java]
String hostedInvoiceUrl = stripe.v1().invoices().retrieve(invoiceId).getHostedInvoiceUrl();
```

```ruby [Ruby]
hosted_invoice_url = stripe.v1.invoices.retrieve(invoice_id).hosted_invoice_url
```

```csharp [.NET]
var hostedInvoiceUrl = (await stripe.V1.Invoices.GetAsync(invoiceId)).HostedInvoiceUrl;
```

:::

Fetch it each time rather than saving the link: Stripe expires it about 30 days after the invoice is finalized.

::: warning Link the hosted page, not the invoice PDF
`invoice_pdf` still shows the amount as due, with a **Pay online** link.
:::

## Good to know

* **Add each order once:** capture returns `captured` again if you call it again. Save the invoice ID with your order, and skip if you already have one.
* **Refunds go through Maytes:** Stripe refunds nothing for this invoice. Use [Maytes refunds](/refunds).
