Getting started

Quickstart

Follow these steps to get an account, an API key and your first converted PDF. Every example here was tested against the real API.

The quick way. Sign up on the website, verify your email and create a key in your dashboard, then go straight to step 4. Steps 1 to 3 show the same thing through the API, for when you want to automate it.

The PHP, Python and Node.js examples read your details from environment variables, so nothing secret goes in your code. You'll need PHP 8 with the curl extension, Python 3 with pip install requests, or Node.js 20 or newer.

1. Create your account

Use a password of at least 10 characters. Set RASTERNIVO_EMAIL and RASTERNIVO_PASSWORD, or put your details in the cURL command.

<?php
$api = getenv('RASTERNIVO_API_URL') ?: 'https://rasternivo-api.swiftinfocorp.com/v1';

$ch = curl_init("$api/auth/register");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode([
        'email' => getenv('RASTERNIVO_EMAIL'),
        'password' => getenv('RASTERNIVO_PASSWORD'),
        'accept_terms' => true,
    ]),
]);
curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), " Check your inbox for the verification email.\n"; // 202
import os
import requests

API = os.environ.get("RASTERNIVO_API_URL", "https://rasternivo-api.swiftinfocorp.com/v1")

r = requests.post(f"{API}/auth/register", json={
    "email": os.environ["RASTERNIVO_EMAIL"],
    "password": os.environ["RASTERNIVO_PASSWORD"],
    "accept_terms": True,
})
print(r.status_code, "Check your inbox for the verification email.")  # 202
const API = process.env.RASTERNIVO_API_URL ?? "https://rasternivo-api.swiftinfocorp.com/v1";

const res = await fetch(`${API}/auth/register`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    email: process.env.RASTERNIVO_EMAIL,
    password: process.env.RASTERNIVO_PASSWORD,
    accept_terms: true,
  }),
});
console.log(res.status, "Check your inbox for the verification email."); // 202
curl -X POST "https://rasternivo-api.swiftinfocorp.com/v1/auth/register" \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com", "password": "choose-a-long-password", "accept_terms": true}'

You get 202 Accepted, and a verification email is on its way. For privacy, the answer is the same whether or not the address already has an account.

2. Verify your email and start your trial

Opening the emailed link verifies you on the website. To do it through the API instead, copy the part of the link after #token= and send it (set it as RASTERNIVO_TOKEN). The link works for 24 hours and can be used once.

<?php
$api = getenv('RASTERNIVO_API_URL') ?: 'https://rasternivo-api.swiftinfocorp.com/v1';

$ch = curl_init("$api/auth/verify-email");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode(['token' => getenv('RASTERNIVO_TOKEN')]),
]);
curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), " Email verified. Your 14-day trial has started.\n";
import os
import requests

API = os.environ.get("RASTERNIVO_API_URL", "https://rasternivo-api.swiftinfocorp.com/v1")

r = requests.post(f"{API}/auth/verify-email", json={"token": os.environ["RASTERNIVO_TOKEN"]})
r.raise_for_status()
print("Email verified. Your 14-day trial has started.")
const API = process.env.RASTERNIVO_API_URL ?? "https://rasternivo-api.swiftinfocorp.com/v1";

const res = await fetch(`${API}/auth/verify-email`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ token: process.env.RASTERNIVO_TOKEN }),
});
if (!res.ok) throw new Error(await res.text());
console.log("Email verified. Your 14-day trial has started.");
curl -X POST "https://rasternivo-api.swiftinfocorp.com/v1/auth/verify-email" \
  -H "Content-Type: application/json" \
  -d '{"token": "THE_TOKEN_FROM_THE_EMAIL"}'

Your 14-day trial starts at this moment: Pro limits and 100 credits, with no card needed.

3. Create an API key

Sign in, then create a key. The full key appears only once, so store it safely, for example as the RASTERNIVO_API_KEY environment variable.

<?php
$api = getenv('RASTERNIVO_API_URL') ?: 'https://rasternivo-api.swiftinfocorp.com/v1';
$email = getenv('RASTERNIVO_EMAIL');
$password = getenv('RASTERNIVO_PASSWORD');

$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIEFILE => '', // keep the session cookie between the two requests
]);

// 1. Sign in
curl_setopt_array($ch, [
    CURLOPT_URL => "$api/auth/login",
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode(['email' => $email, 'password' => $password]),
]);
$login = json_decode(curl_exec($ch), true);

// 2. Create the key
curl_setopt_array($ch, [
    CURLOPT_URL => "$api/api-keys",
    CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'X-CSRF-Token: ' . $login['csrf_token']],
    CURLOPT_POSTFIELDS => json_encode([
        'label' => 'my-server',
        'scopes' => ['conversions:read', 'conversions:write', 'usage:read'],
        'password' => $password, // asked again because a key is a long-lived credential
    ]),
]);
$key = json_decode(curl_exec($ch), true);

echo $key['secret'], "\n"; // shown only once: store it safely
import os
import requests

API = os.environ.get("RASTERNIVO_API_URL", "https://rasternivo-api.swiftinfocorp.com/v1")
email = os.environ["RASTERNIVO_EMAIL"]
password = os.environ["RASTERNIVO_PASSWORD"]

session = requests.Session()  # keeps the session cookie between requests

# 1. Sign in
login = session.post(f"{API}/auth/login", json={"email": email, "password": password})
login.raise_for_status()

# 2. Create the key
r = session.post(
    f"{API}/api-keys",
    headers={"X-CSRF-Token": login.json()["csrf_token"]},
    json={
        "label": "my-server",
        "scopes": ["conversions:read", "conversions:write", "usage:read"],
        "password": password,  # asked again because a key is a long-lived credential
    },
)
r.raise_for_status()

print(r.json()["secret"])  # shown only once: store it safely
const API = process.env.RASTERNIVO_API_URL ?? "https://rasternivo-api.swiftinfocorp.com/v1";
const email = process.env.RASTERNIVO_EMAIL;
const password = process.env.RASTERNIVO_PASSWORD;

// 1. Sign in
const login = await fetch(`${API}/auth/login`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ email, password }),
});
if (!login.ok) throw new Error(await login.text());
const { csrf_token } = await login.json();
const cookie = login.headers.getSetCookie().map((c) => c.split(";")[0]).join("; ");

// 2. Create the key
const res = await fetch(`${API}/api-keys`, {
  method: "POST",
  headers: { "Content-Type": "application/json", "X-CSRF-Token": csrf_token, Cookie: cookie },
  body: JSON.stringify({
    label: "my-server",
    scopes: ["conversions:read", "conversions:write", "usage:read"],
    password, // asked again because a key is a long-lived credential
  }),
});
if (!res.ok) throw new Error(await res.text());

console.log((await res.json()).secret); // shown only once: store it safely
API="https://rasternivo-api.swiftinfocorp.com/v1"

# 1. Sign in. The cookie is saved to session.txt; copy csrf_token from the response.
curl -c session.txt -X POST "$API/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com", "password": "your-password"}'

# 2. Create the key, sending the cookie, the CSRF token and your password again.
curl -b session.txt -X POST "$API/api-keys" \
  -H "Content-Type: application/json" \
  -H "X-CSRF-Token: CSRF_TOKEN_FROM_STEP_1" \
  -d '{"label": "my-server",
       "scopes": ["conversions:read", "conversions:write", "usage:read"],
       "password": "your-password"}'

The response looks like this:

{
  "api_key": {
    "id": "01a19b62-dbe2-7c45-b0ce-5ce02d942a49",
    "prefix": "rn_live_qb3tqt2dfhbn",
    "label": "my-server",
    "scopes": ["conversions:read", "conversions:write", "usage:read"],
    "created_at": "2026-11-02T08:31:49Z",
    "last_used_at": null, "expires_at": null, "revoked_at": null
  },
  "secret": "rn_live_qb3tqt2dfhbn_…",
  "notice": "Copy this key now. It will not be shown again."
}

4. Check your trial

<?php
$api = getenv('RASTERNIVO_API_URL') ?: 'https://rasternivo-api.swiftinfocorp.com/v1';

$ch = curl_init("$api/usage");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('RASTERNIVO_API_KEY')],
]);
$usage = json_decode(curl_exec($ch), true);

echo $usage['plan']['name'], ' (', $usage['plan']['source'], '): ',
     $usage['credits']['available'], " credits available\n";
import os
import requests

API = os.environ.get("RASTERNIVO_API_URL", "https://rasternivo-api.swiftinfocorp.com/v1")

usage = requests.get(
    f"{API}/usage",
    headers={"Authorization": "Bearer " + os.environ["RASTERNIVO_API_KEY"]},
).json()

print(f"{usage['plan']['name']} ({usage['plan']['source']}): "
      f"{usage['credits']['available']} credits available")
const API = process.env.RASTERNIVO_API_URL ?? "https://rasternivo-api.swiftinfocorp.com/v1";

const res = await fetch(`${API}/usage`, {
  headers: { Authorization: `Bearer ${process.env.RASTERNIVO_API_KEY}` },
});
const usage = await res.json();

console.log(`${usage.plan.name} (${usage.plan.source}): ${usage.credits.available} credits available`);
curl "https://rasternivo-api.swiftinfocorp.com/v1/usage" \
  -H "Authorization: Bearer $RASTERNIVO_API_KEY"

This prints Pro (trial): 100 credits available. The full response is in Free trial and credits.

5. Convert a PDF

Put a file named report.pdf in your folder and run this. It uploads the PDF, waits for the job, and saves each page as a JPG.

<?php
$api = getenv('RASTERNIVO_API_URL') ?: 'https://rasternivo-api.swiftinfocorp.com/v1';
$key = getenv('RASTERNIVO_API_KEY');

function get_json(string $url, string $key): array
{
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => ["Authorization: Bearer $key"],
    ]);
    return json_decode(curl_exec($ch), true);
}

// 1. Upload. The options field must come before the file.
$ch = curl_init("$api/conversions");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer $key",
        'Idempotency-Key: ' . bin2hex(random_bytes(16)),
    ],
    CURLOPT_POSTFIELDS => [
        'options' => json_encode(['pages' => 'all', 'dpi' => 150, 'quality' => 90, 'zip' => true]),
        'file' => new CURLFile('report.pdf', 'application/pdf'),
    ],
]);
$job = json_decode(curl_exec($ch), true);
if (curl_getinfo($ch, CURLINFO_RESPONSE_CODE) !== 202) {
    exit('Upload failed: ' . $job['error']['message'] . "\n");
}

// 2. Wait until the job ends.
while (!in_array($job['state'], ['succeeded', 'failed', 'cancelled', 'expired'])) {
    sleep(2);
    $job = get_json("$api/conversions/{$job['id']}", $key);
}
if ($job['state'] !== 'succeeded') {
    exit('Conversion ' . $job['state'] . ': ' . ($job['error']['message'] ?? '') . "\n");
}

// 3. Download every page. The links need no API key and expire after 15 minutes.
$result = get_json("$api/conversions/{$job['id']}/result", $key);
foreach ($result['pages'] as $page) {
    if (!empty($page['url'])) {
        file_put_contents(basename($page['filename']), file_get_contents($page['url']));
        echo 'Saved ', $page['filename'], "\n";
    }
}
echo 'Credits used: ', $job['credits_consumed'], "\n";
import json
import os
import time
import uuid

import requests

API = os.environ.get("RASTERNIVO_API_URL", "https://rasternivo-api.swiftinfocorp.com/v1")
headers = {"Authorization": "Bearer " + os.environ["RASTERNIVO_API_KEY"]}

# 1. Upload. requests sends the options field before the file, as the API needs.
options = {"pages": "all", "dpi": 150, "quality": 90, "zip": True}
with open("report.pdf", "rb") as pdf:
    r = requests.post(
        f"{API}/conversions",
        headers={**headers, "Idempotency-Key": str(uuid.uuid4())},
        data={"options": json.dumps(options)},
        files={"file": ("report.pdf", pdf, "application/pdf")},
    )
if r.status_code != 202:
    raise SystemExit("Upload failed: " + r.json()["error"]["message"])
job = r.json()

# 2. Wait until the job ends.
while job["state"] not in ("succeeded", "failed", "cancelled", "expired"):
    time.sleep(2)
    job = requests.get(f"{API}/conversions/{job['id']}", headers=headers).json()
if job["state"] != "succeeded":
    raise SystemExit(f"Conversion {job['state']}: {job['error']}")

# 3. Download every page. The links need no API key and expire after 15 minutes.
result = requests.get(f"{API}/conversions/{job['id']}/result", headers=headers).json()
for page in result["pages"]:
    if page.get("url"):
        with open(os.path.basename(page["filename"]), "wb") as out:
            out.write(requests.get(page["url"]).content)
        print("Saved", page["filename"])
print("Credits used:", job["credits_consumed"])
// Node.js 20 or newer: no packages needed.
import { randomUUID } from "node:crypto";
import { readFile, writeFile } from "node:fs/promises";
import { basename } from "node:path";
import { setTimeout as sleep } from "node:timers/promises";

const API = process.env.RASTERNIVO_API_URL ?? "https://rasternivo-api.swiftinfocorp.com/v1";
const headers = { Authorization: `Bearer ${process.env.RASTERNIVO_API_KEY}` };
const getJson = async (path) => (await fetch(API + path, { headers })).json();

// 1. Upload. The options field must come before the file.
const form = new FormData();
form.append("options", JSON.stringify({ pages: "all", dpi: 150, quality: 90, zip: true }));
form.append("file", new Blob([await readFile("report.pdf")], { type: "application/pdf" }), "report.pdf");

const res = await fetch(`${API}/conversions`, {
  method: "POST",
  headers: { ...headers, "Idempotency-Key": randomUUID() },
  body: form,
});
let job = await res.json();
if (res.status !== 202) throw new Error(`Upload failed: ${job.error.message}`);

// 2. Wait until the job ends.
while (!["succeeded", "failed", "cancelled", "expired"].includes(job.state)) {
  await sleep(2000);
  job = await getJson(`/conversions/${job.id}`);
}
if (job.state !== "succeeded") throw new Error(`Conversion ${job.state}: ${job.error?.message}`);

// 3. Download every page. The links need no API key and expire after 15 minutes.
const result = await getJson(`/conversions/${job.id}/result`);
for (const page of result.pages) {
  if (page.url) {
    const file = await fetch(page.url);
    await writeFile(basename(page.filename), Buffer.from(await file.arrayBuffer()));
    console.log("Saved", page.filename);
  }
}
console.log("Credits used:", job.credits_consumed);
API="https://rasternivo-api.swiftinfocorp.com/v1"

# 1. Upload. The options part must come before the file part.
curl -X POST "$API/conversions" \
  -H "Authorization: Bearer $RASTERNIVO_API_KEY" \
  -H "Idempotency-Key: report-2026-11-02-001" \
  -F 'options={"pages": "all", "dpi": 150, "quality": 90, "zip": true}' \
  -F "file=@report.pdf;type=application/pdf"

# 2. Check the job until "state" is succeeded, failed or cancelled.
curl "$API/conversions/JOB_ID" -H "Authorization: Bearer $RASTERNIVO_API_KEY"

# 3. Get the download links, then download.
curl "$API/conversions/JOB_ID/result" -H "Authorization: Bearer $RASTERNIVO_API_KEY"
curl -o report.zip "ZIP_URL_FROM_THE_RESULT"

You'll see each file being saved:

Saved report_page_0001.jpg
Saved report_page_0002.jpg
…
Credits used: 10

Next steps