Skip to main content
Make sure your integration already wraps requests with fetchWithPayment so Coinbase x402 challenges are paid automatically.

1. Configure the spreadsheet extraction

const baseUrl = process.env.HORIZON_BASE_URL ?? 'https://api.horizon.new/v1';

const sheetResponse = await fetchWithPayment(`${baseUrl}/extract/spreadsheet`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    sourceUrl: 'https://cdn.example.com/reports/sales-q1-2025.xlsx',
    sourceName: 'Sales Q1 2025',
    options: {
      sheet: 'Summary',
      headerRow: 2,
      dateFormat: 'yyyy-MM-dd',
    },
    webhookUrl: 'https://example.com/webhooks/horizon/extraction',
  }),
});

const sheetJob = await sheetResponse.json();
console.log('sheet job', sheetJob.jobId);

2. Handle synchronous completion

if (sheetJob.status === 'completed' && sheetJob.result) {
  console.log('Inline tables', sheetJob.result.tables?.[0]?.rows.length ?? 0);
}

3. Poll for completion

const status = await fetchWithPayment(sheetJob.statusUrl).then((res) => res.json());

if (status.state === 'processing') {
  await new Promise((resolve) => setTimeout(resolve, 2000));
}

if (status.state !== 'succeeded') {
  throw new Error(`Spreadsheet extraction failed: ${status.error?.code ?? 'unknown'}`);
}

console.log('rows extracted', status.result.tables?.[0]?.rows.length ?? 0);

4. Use the tables

  • Upsert rows into your analytics warehouse or CRM.
  • Attach your own annotations to the resulting records for discovery via /search.
  • Compare consecutive exports by storing status.result.version markers.