Expanding responses

Inline related objects to reduce round-trips.

View as Markdown

By default the VINR API returns related objects as ID strings to keep responses small and fast. The expand parameter lets you inline the full object in the same response, so you can fetch a payment and its customer, or an invoice and its line items, in a single round-trip instead of two or three.

The expand parameterAsk

Many objects reference others by ID. A payment, for example, carries a customer field holding a cust_ string. To receive the full customer object inline, pass expand with the field path:

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

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

const payment = await vinr.payments.retrieve('pay_3Nx8a2Lk', {
  expand: ['customer'],
});

// payment.customer is now the full object, not just "cust_8aZ2"
console.log(payment.customer.email);
curl https://api.vinr.com/v1/payments/pay_3Nx8a2Lk \
  -H "X-Api-Key: $VINR_SECRET_KEY" \
  -d "expand[]=customer" \
  -G

expand is an array of strings, so request several fields at once: expand: ['customer', 'refunds']. It works on retrieve, create, update, and list endpoints — anywhere the API returns an expandable object.

Expanding never changes which object you get back, only how much of it is materialized. An unexpanded field is always the ID string; an expanded one is the nested object. Write your code to handle both shapes if the same path is reused across calls.

Expandable fieldsAsk

Each resource documents which of its fields can be expanded. The most commonly used paths:

ResourceExpandable fieldResolves to
paymentcustomerThe customer object
paymentrefundsList of refund objects
paymentdisputeThe dispute object, if any
invoicecustomerThe customer object
invoicesubscriptionThe subscription object
invoicelines.priceThe price on each line item
subscriptioncustomerThe customer object
subscriptionlatest_invoiceThe most recent invoice
redemptionrewardThe reward object
loyalty_accountcustomerThe customer object

Fields not listed as expandable return their ID string regardless of what you pass. Requesting an unknown or non-expandable path returns a 400 with code: "invalid_expand".

Nested expansionAsk

Use dot notation to expand through one object into another. For example, a subscription's latest invoice has a customer of its own:

const sub = await vinr.subscriptions.retrieve('sub_9Kpw1Vd', {
  expand: ['latest_invoice.customer'],
});

console.log(sub.latest_invoice.customer.email);

Expanding a nested path automatically expands its parents — you do not need to also list latest_invoice separately. To expand a field on every element of a list, name the list followed by the field: lines.price expands the price on each line of an invoice.

const invoice = await vinr.invoices.retrieve('inv_2Qm4eRt', {
  expand: ['lines.price', 'subscription'],
});

for (const line of invoice.lines) {
  console.log(line.price.unit_amount, line.price.currency);
}

Expanding inside list responsesAsk

On list endpoints, prefix the path with data to expand the field on each returned object. The expansion applies uniformly to every item in the page:

const payments = await vinr.payments.list({
  limit: 20,
  expand: ['data.customer'],
});

for (const payment of payments.data) {
  console.log(payment.id, payment.customer.email);
}

This is the single most effective way to avoid N+1 fetch loops when rendering tables or running reconciliation jobs over a page of results.

LimitsAsk

Expansion is powerful but bounded, so a single request cannot trigger unbounded fan-out:

Prop

Type

Each expanded path adds work to the request and counts toward your rate limit the same as a separate read. Deep or list-wide expansion increases latency — expand only what you render. For large or paginated child collections, prefer the dedicated list endpoint (for example vinr.refunds.list({ payment })) over inline expansion.

Expansion never affects webhook payloads. Events such as payment.completed always deliver the unexpanded object; resolve related records by calling the API from your handler if you need them.

Next stepsAsk

Was this page helpful?