> ## Documentation Index
> Fetch the complete documentation index at: https://docs.shoppex.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Reviews & Invoices

> Fetch shop reviews and invoice status

## Reviews

### getShopReviews

Fetches all public reviews for the store.

```javascript theme={"system"}
const { data: reviews } = await shoppex.getShopReviews();

reviews.forEach(review => {
  console.log(review.rating, review.comment);
});
```

### Response

<ResponseField name="data" type="Feedback[]">
  <Expandable title="Feedback object">
    <ResponseField name="id" type="string">
      Review unique identifier
    </ResponseField>

    <ResponseField name="rating" type="number">
      Star rating (1-5)
    </ResponseField>

    <ResponseField name="comment" type="string">
      Review text
    </ResponseField>

    <ResponseField name="created_at" type="string">
      ISO timestamp
    </ResponseField>
  </Expandable>
</ResponseField>

### Example: Reviews Section

```javascript theme={"system"}
async function renderReviews() {
  const { data: reviews } = await shoppex.getShopReviews();
  const container = document.getElementById('reviews');

  // Calculate average
  const avgRating = reviews.reduce((sum, r) => sum + r.rating, 0) / reviews.length;

  container.innerHTML = `
    <div class="reviews-header">
      <h2>Customer Reviews</h2>
      <div class="average">
        ${'★'.repeat(Math.round(avgRating))}${'☆'.repeat(5 - Math.round(avgRating))}
        <span>${avgRating.toFixed(1)} / 5</span>
        <span>(${reviews.length} reviews)</span>
      </div>
    </div>

    <div class="reviews-list">
      ${reviews.map(review => `
        <div class="review">
          <div class="stars">${'★'.repeat(review.rating)}${'☆'.repeat(5 - review.rating)}</div>
          <p class="comment">${review.comment || ''}</p>
          <span class="date">${new Date(review.created_at).toLocaleDateString()}</span>
        </div>
      `).join('')}
    </div>
  `;
}
```

## Invoices

### getInvoice

Fetches full invoice details.

```javascript theme={"system"}
const { data: invoice } = await shoppex.getInvoice('inv_abc123');

console.log(invoice.status);   // "COMPLETED"
console.log(invoice.total);    // 29.99
console.log(invoice.products); // [{ title, quantity, price }]
```

### Response

<ResponseField name="data" type="Invoice">
  <Expandable title="Invoice object">
    <ResponseField name="uniqid" type="string">
      Invoice unique identifier
    </ResponseField>

    <ResponseField name="status" type="string">
      Invoice status (PENDING, COMPLETED, CANCELLED, etc.)
    </ResponseField>

    <ResponseField name="total" type="number">
      Total amount
    </ResponseField>

    <ResponseField name="currency" type="string">
      Currency code
    </ResponseField>

    <ResponseField name="products" type="InvoiceProduct[]">
      Purchased products
    </ResponseField>
  </Expandable>
</ResponseField>

### getInvoiceStatus

Lightweight endpoint for status polling. Use this instead of `getInvoice` for real-time updates.

```javascript theme={"system"}
const { data } = await shoppex.getInvoiceStatus('inv_abc123');
console.log(data.status); // "PENDING" | "COMPLETED" | "CANCELLED"
```

### Example: Order Status Page

```javascript theme={"system"}
async function pollOrderStatus(invoiceId) {
  const statusEl = document.getElementById('order-status');

  const checkStatus = async () => {
    const { data } = await shoppex.getInvoiceStatus(invoiceId);

    switch (data.status) {
      case 'PENDING':
        statusEl.innerHTML = '<span class="pending">Waiting for payment...</span>';
        break;
      case 'PROCESSING':
        statusEl.innerHTML = '<span class="processing">Processing payment...</span>';
        break;
      case 'COMPLETED':
        statusEl.innerHTML = '<span class="success">Order complete! Check your email.</span>';
        clearInterval(pollInterval);
        break;
      case 'CANCELLED':
        statusEl.innerHTML = '<span class="error">Order cancelled</span>';
        clearInterval(pollInterval);
        break;
    }
  };

  // Poll every 5 seconds
  const pollInterval = setInterval(checkStatus, 5000);
  checkStatus(); // Initial check
}

// Get invoice ID from URL
const invoiceId = new URLSearchParams(window.location.search).get('invoice');
if (invoiceId) {
  pollOrderStatus(invoiceId);
}
```

## Formatting Utilities

### formatPrice

Formats a price with currency symbol.

```javascript theme={"system"}
shoppex.formatPrice(29.99, 'USD');       // "$29.99"
shoppex.formatPrice(29.99, 'EUR');       // "€29.99"
shoppex.formatPrice(29.99, 'EUR', 'de'); // "29,99 €"
```

### Parameters

<ParamField path="amount" type="number" required>
  Price amount
</ParamField>

<ParamField path="currency" type="string" default="Store currency">
  ISO 4217 currency code
</ParamField>

<ParamField path="locale" type="string" default="en">
  Locale for formatting
</ParamField>

### createFormatter

Creates a reusable `Intl.NumberFormat` instance.

```javascript theme={"system"}
const formatter = shoppex.createFormatter('EUR', 'de');

formatter.format(29.99);  // "29,99 €"
formatter.format(100);    // "100,00 €"
```

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Products API" icon="box" href="/sdk/api/products">
    Fetch products, variants, and categories
  </Card>

  <Card title="SDK Types" icon="code" href="/sdk/types">
    Full TypeScript type reference
  </Card>
</CardGroup>
