# Node.js Integration — RenderPix

**API Endpoint:** `POST https://renderpix.dev/v1/render`

---

## Authentication

Pass your API key in the `X-API-Key` header on every request.

```js
const API_KEY = 'rpx_your_api_key';
const ENDPOINT = 'https://renderpix.dev/v1/render';
```

---

## Basic Example — HTML to PNG (fetch)

```js
const fs = require('fs');

async function renderHtml(html, outputFile = 'output.png') {
  const res = await fetch('https://renderpix.dev/v1/render', {
    method: 'POST',
    headers: {
      'X-API-Key': 'rpx_your_api_key',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      html,
      width: 1200,
      height: 630,
      format: 'png',
    }),
  });

  if (!res.ok) {
    const err = await res.json().catch(() => ({}));
    throw new Error(`RenderPix error ${res.status}: ${err.message || res.statusText}`);
  }

  const buffer = Buffer.from(await res.arrayBuffer());
  fs.writeFileSync(outputFile, buffer);
  console.log(`Saved to ${outputFile}`);
}

renderHtml('<h1 style="font-family:sans-serif;color:#1e293b">Hello, RenderPix!</h1>');
```

---

## Basic Example — HTML to PNG (axios)

```js
const axios = require('axios');
const fs = require('fs');

async function renderHtml(html, outputFile = 'output.png') {
  const response = await axios.post(
    'https://renderpix.dev/v1/render',
    { html, width: 1200, height: 630, format: 'png' },
    {
      headers: {
        'X-API-Key': 'rpx_your_api_key',
        'Content-Type': 'application/json',
      },
      responseType: 'arraybuffer',
    }
  );

  fs.writeFileSync(outputFile, response.data);
  console.log(`Saved to ${outputFile}`);
}

renderHtml('<h1 style="font-family:sans-serif">Hello!</h1>');
```

---

## Real-World Example — OG Image Generator

```js
const fs = require('fs');

async function generateOgImage({ title, description, domain, outputFile = 'og.png' }) {
  const html = `<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body {
      width: 1200px; height: 630px; overflow: hidden;
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
      background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
      display: flex; align-items: center; justify-content: center; padding: 80px;
    }
    .card {
      display: flex; flex-direction: column; gap: 24px; width: 100%;
    }
    .domain {
      font-size: 20px; font-weight: 600; color: #38bdf8;
      text-transform: uppercase; letter-spacing: 2px;
    }
    h1 {
      font-size: 72px; font-weight: 800; color: #f1f5f9;
      line-height: 1.1; letter-spacing: -2px;
    }
    p {
      font-size: 28px; color: #94a3b8; line-height: 1.5;
    }
  </style>
</head>
<body>
  <div class="card">
    <div class="domain">${domain}</div>
    <h1>${title}</h1>
    <p>${description}</p>
  </div>
</body>
</html>`;

  const res = await fetch('https://renderpix.dev/v1/render', {
    method: 'POST',
    headers: {
      'X-API-Key': 'rpx_your_api_key',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ html, width: 1200, height: 630, format: 'png' }),
  });

  if (!res.ok) {
    const err = await res.json().catch(() => ({}));
    throw new Error(`Render failed (${res.status}): ${err.message || res.statusText}`);
  }

  const buffer = Buffer.from(await res.arrayBuffer());
  fs.writeFileSync(outputFile, buffer);
  return outputFile;
}

// Usage
generateOgImage({
  title: 'Build Faster with RenderPix',
  description: 'HTML to image in one API call. No puppeteer, no headless browser.',
  domain: 'renderpix.dev',
  outputFile: 'og-image.png',
}).then(file => console.log('OG image saved:', file));
```

---

## Response Handling

A successful render returns the image binary directly (`Content-Type: image/png` or `image/webp`).

```js
const res = await fetch('https://renderpix.dev/v1/render', { /* ... */ });

// Check status first
if (res.status === 200) {
  const contentType = res.headers.get('content-type'); // 'image/png'
  const buffer = Buffer.from(await res.arrayBuffer());
  // buffer contains the raw image bytes
}
```

---

## Error Handling

```js
async function renderSafe(html) {
  let res;
  try {
    res = await fetch('https://renderpix.dev/v1/render', {
      method: 'POST',
      headers: {
        'X-API-Key': 'rpx_your_api_key',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ html, width: 1200, height: 630 }),
    });
  } catch (networkErr) {
    console.error('Network error:', networkErr.message);
    return null;
  }

  if (!res.ok) {
    const body = await res.json().catch(() => ({}));
    switch (res.status) {
      case 401: throw new Error('Invalid API key — check X-API-Key header');
      case 429: throw new Error('Rate limit exceeded — slow down or upgrade plan');
      case 422: throw new Error(`Invalid request: ${body.message}`);
      default:  throw new Error(`Render failed (${res.status}): ${body.message || 'unknown error'}`);
    }
  }

  return Buffer.from(await res.arrayBuffer());
}
```

---

## Next.js / Edge Runtime Example

```js
// app/api/og/route.js
export async function GET(request) {
  const { searchParams } = new URL(request.url);
  const title = searchParams.get('title') || 'Untitled';

  const html = `<html><body style="margin:0;background:#0f172a;display:flex;align-items:center;justify-content:center;width:1200px;height:630px"><h1 style="color:#f1f5f9;font-family:sans-serif;font-size:80px">${title}</h1></body></html>`;

  const res = await fetch('https://renderpix.dev/v1/render', {
    method: 'POST',
    headers: {
      'X-API-Key': process.env.RENDERPIX_API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ html, width: 1200, height: 630, format: 'png' }),
  });

  if (!res.ok) return new Response('Render failed', { status: 500 });

  const image = await res.arrayBuffer();
  return new Response(image, {
    headers: { 'Content-Type': 'image/png', 'Cache-Control': 'public, max-age=86400' },
  });
}
```
