PaymentsUnified commerceEndless aisle

Endless aisle

Let in-store shoppers buy items not in stock at that location — ordered and paid for at the terminal, shipped to home.

View as MarkdownInstall skills

Endless aisle removes the constraint of physical shelf space: your store can sell any item in your full catalogue, not just what happens to be stocked at that location. A staff member uses a kiosk or tablet to browse live inventory, the customer pays at the terminal as they would for any in-store purchase, and the item ships directly from a warehouse or another store branch. VINR handles the payment leg; your order management system (OMS) owns fulfilment.

How it worksAsk

Staff finds the item in your catalogue. On the store's POS or a tablet browser, the associate searches your OMS for the item the customer wants. The OMS returns live stock levels across all locations and warehouses.

OMS creates a ship-to-home order. Before touching VINR, your OMS creates an order record with the customer's shippingAddress and the fulfilment source (warehouse ID or store branch). Note the orderId — you will attach it to the VINR payment.

Backend creates a terminal payment with order metadata. Your server calls vinr.terminal.payments.create with metadata.orderId, metadata.fulfillment, and metadata.shippingAddress so the payment record is permanently linked to the shipment.

Customer taps to pay. The terminal prompts the customer to present their card or device. The transaction authorises and captures in a single pass.

OMS receives the confirmation and triggers fulfilment. Your backend listens for the payment.completed webhook, looks up the order by metadata.orderId, and instructs the OMS to release the shipment.

Standard payment.completed webhook confirms payment. VINR delivers the webhook within milliseconds of authorisation. No polling required.

Integration patternAsk

Your OMS and VINR are the two systems involved. VINR is payment-only — it never writes to your inventory or triggers a shipment. All fulfilment logic lives in your OMS; VINR provides the payment ID and metadata that your OMS uses to correlate records.

Create the terminal payment from your server after the OMS order exists:

import { Vinr } from '@vinr/sdk';

const vinr = new Vinr({ secretKey: process.env.VINR_SECRET_KEY });

const terminalPayment = await vinr.terminal.payments.create({
  terminalId: 'term_01HZ5QXYZ',
  amount: 14900,
  currency: 'USD',
  reference: 'order_9934',
  metadata: {
    orderId: 'order_9934',
    fulfillment: 'ship_from_warehouse',
    shippingAddress: JSON.stringify({
      name: 'Alex Sharkov',
      line1: '123 Main St',
      city: 'Brooklyn',
      state: 'NY',
      postalCode: '11201',
      country: 'US',
    }),
  },
});

In your payment.completed webhook handler, retrieve the metadata to link payment back to the order:

app.post('/webhooks/vinr', (req, res) => {
  const event = req.body;

  if (event.type === 'payment.completed') {
    const { orderId, fulfillment } = event.data.metadata;
    oms.releaseShipment({ orderId, fulfillment });
  }

  res.sendStatus(200);
});

Metadata field reference

Prop

Type

ReceiptsAsk

The customer receives a receipt confirming both the payment and the shipping details. Populate receiptData on the terminal payment to embed the order number and estimated delivery date directly on the printed or emailed receipt:

const terminalPayment = await vinr.terminal.payments.create({
  terminalId: 'term_01HZ5QXYZ',
  amount: 14900,
  currency: 'USD',
  reference: 'order_9934',
  metadata: {
    orderId: 'order_9934',
    fulfillment: 'ship_from_warehouse',
    shippingAddress: JSON.stringify({
      name: 'Alex Sharkov',
      line1: '123 Main St',
      city: 'Brooklyn',
      state: 'NY',
      postalCode: '11201',
      country: 'US',
    }),
  },
  receiptData: {
    lineItems: [
      { description: 'Blue Suede Shoes (size 10)', amount: 14900 },
    ],
    footer: 'Order #9934 · Est. delivery: Jun 4 – Jun 6',
  },
});

The footer line appears on paper receipts and in the email receipt body. For full receipt configuration options — including email and SMS delivery channels — see Receipts & shopper engagement.

Refunds and returnsAsk

If the item arrives damaged or the wrong size, the refund is processed from your backend — not at the original terminal — because the customer is no longer in the store.

import { Vinr } from '@vinr/sdk';

const vinr = new Vinr({ secretKey: process.env.VINR_SECRET_KEY });

const refund = await vinr.refunds.create({
  payment: 'tpy_01HZ5QA7BK',
  reason: 'product_not_received',
  metadata: { orderId: 'order_9934', returnTicket: 'RT-221' },
});

For customers who physically return an endless-aisle item to any store location, see Return in-store. That flow handles scanning the original payment ID at a terminal and issuing a card-present refund.

Next stepsAsk

Was this page helpful?
Edit on GitHub

Last updated on

On this page