Skip to main content

Prerequisites

  • Set HORIZON_BASE_URL if you target staging or a sandbox; production defaults to https://api.horizon.new/v1.

Using fetch in Node.js

import fetch from 'node-fetch';

const baseUrl = process.env.HORIZON_BASE_URL ?? 'https://api.horizon.new/v1';
const response = await fetch(`${baseUrl}/search?q=astral%20libraries`);

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

const results = await response.json();
console.log(results.items[0]);
Swap fetch for your preferred HTTP library (Axios, Got, requests, etc.)—the contract is simple JSON over HTTPS.

Submitting jobs

const jobRes = await fetch(`${baseUrl}/generate/text`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    prompt: 'Write a welcome note for new Horizon users.',
    webhookUrl: 'https://example.com/webhooks/horizon',
  }),
});

if (jobRes.status === 402) {
  const payment = await jobRes.json();
  // Replay using Coinbase buyer quickstart:
  // https://docs.cdp.coinbase.com/x402/quickstart-for-buyers
  throw new Error(`Payment required: ${payment.accepts[0].resource}`);
}

const job = await jobRes.json();
console.log(job.jobId, job.statusUrl);

Polling job status

const status = await fetch(`${baseUrl}/jobs/${job.jobId}`).then((res) => res.json());

if (status.state === 'succeeded') {
  console.log(status.result);
} else if (status.state === 'failed') {
  console.error(status.error);
}
Use exponential backoff or respect Retry-After headers when polling long-running jobs.

Uploading files

For extraction endpoints you can send either a URL or a file upload. In Node.js, use FormData:
import FormData from 'form-data';
import { createReadStream } from 'node:fs';

const form = new FormData();
form.append('file', createReadStream('./guides/onboarding.pdf'));

const upload = await fetch(`${baseUrl}/extract/pdf`, {
  method: 'POST',
  body: form,
});

const uploadJob = await upload.json();
console.log(uploadJob.jobId);

Handling errors

  • 402 Payment Required – Follow Coinbase’s Quickstart for buyers to replay with X-PAYMENT.
  • 429 Too Many Requests – Respect Retry-After or back off before retrying.
  • 4xx validation errors – Inspect the JSON body for fieldErrors and surface them in your UI.
  • 5xx – Retry with jitter or escalate to support with the requestId header.