Onboarding health dashboard

Get a single, at-a-glance view of how every onboarding is going — how far along each account is, what's overdue, and who's falling behind — and drop it into a spreadsheet, a dashboard, or a weekly email.

What you'll get

A row for every active account, ready to open in Excel or Google Sheets:

Example output · onboarding_health_sample.csv
projectstatuscompleted_%overduedue_soon
Acme Health rolloutIn Progress7213
Globex onboardingIn Progress4542
Initech data migrationOn Track8801
Umbrella Corp setupAt Risk2365
Wayne Enterprises portalOn Track9500
Stark Industries kickoffIn Progress6124
Download onboarding_health_sample.csv279 B

Feed that same data into a chart and it becomes a health dashboard like this:

Is this for me?

Yes, if you lead a CS or onboarding team and want your numbers outside OnRamp — in the tools you already report from. You do not need to be a developer. If you can copy and paste a line of text, you can run the first step; the full report is a short script you can hand to anyone technical (or paste into an AI assistant and ask it to run).

You'll need: about 10 minutes and an API key.

Step 1 — Get your API key

In OnRamp, go to Settings → API and create a key. Copy it somewhere safe — you'll paste it into the examples below in place of YOUR_API_KEY.

Not seeing the API settings? The API is available on Pro and Premier plans. Your account manager can turn it on.

Step 2 — Confirm it works (one line)

Paste this into your terminal, swapping in your key. It asks OnRamp for your list of projects and prints the result — proof your key works before you go further.

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://api.onramp.us/v1/projects"
import requests

resp = requests.get(
    "https://api.onramp.us/v1/projects",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
)
print(resp.json())
const resp = await fetch("https://api.onramp.us/v1/projects", {
  headers: { Authorization: "Bearer YOUR_API_KEY" },
});
console.log(await resp.json());

If you get back a block of JSON with your projects in it, you're ready.

Step 3 — Build the full report

This walks through every project, adds up overdue and due-soon work, and writes the spreadsheet shown above. Pick your language, paste in your key, and run it.

# curl is great for one call at a time, but building the full spreadsheet
# means looping over every project and counting tasks — that's much easier
# in Python or Node. The building blocks, if you want to script it yourself:

# 1. List projects (name, status, completion %)
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://api.onramp.us/v1/projects?page=1&limit=100"

# 2. Count overdue tasks for one project (read data.pagination.total in the reply)
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://api.onramp.us/v1/tasks?project_uuid=PROJECT_UUID&is_overdue=true&limit=1"

# 3. Count work due in the next 7 days
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://api.onramp.us/v1/tasks?project_uuid=PROJECT_UUID&due_date_before=2026-08-30&limit=1"
import csv, datetime as dt, requests

BASE = "https://api.onramp.us/v1"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}
SOON = (dt.date.today() + dt.timedelta(days=7)).isoformat()

def pages(path, list_key, params=None):
    """Walk every page; lists live at data.<resource>, paging at data.pagination."""
    page = 1
    while page:
        body = requests.get(f"{BASE}{path}", headers=HEADERS,
                            params=dict(params or {}, page=page, limit=100)).json()
        yield from body["data"][list_key]
        page = body["data"]["pagination"]["nextPage"]  # None on the last page

def total(path, params):  # count matches without downloading them
    body = requests.get(f"{BASE}{path}", headers=HEADERS,
                        params=dict(params, page=1, limit=1)).json()
    return body["data"]["pagination"]["total"]

with open("onboarding_health.csv", "w", newline="") as f:
    out = csv.writer(f)
    out.writerow(["project", "status", "completed_%", "overdue", "due_soon"])
    for p in pages("/projects", "projects"):
        uuid = p["uuid"]
        out.writerow([
            p["name"], p["status"]["name"], p["completed_percentage"],
            total("/tasks", {"project_uuid": uuid, "is_overdue": "true"}),
            total("/tasks", {"project_uuid": uuid, "due_date_before": SOON}),
        ])
print("Wrote onboarding_health.csv")
import { writeFileSync } from "node:fs";

const BASE = "https://api.onramp.us/v1";
const HEADERS = { Authorization: "Bearer YOUR_API_KEY" };
const soon = new Date(Date.now() + 7 * 864e5).toISOString().slice(0, 10);

const get = async (path, params) => {
  const url = new URL(BASE + path);
  Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
  return (await fetch(url, { headers: HEADERS })).json();
};

// Lists live at data.<resource>; paging info at data.pagination.
async function* pages(path, listKey) {
  let page = 1;
  while (page) {
    const { data } = await get(path, { page, limit: 100 });
    yield* data[listKey];
    page = data.pagination.nextPage; // null on the last page
  }
}

const total = async (path, params) =>
  (await get(path, { ...params, page: 1, limit: 1 })).data.pagination.total;

const rows = [["project", "status", "completed_%", "overdue", "due_soon"]];
for await (const p of pages("/projects", "projects")) {
  rows.push([
    p.name, p.status.name, p.completed_percentage,
    await total("/tasks", { project_uuid: p.uuid, is_overdue: "true" }),
    await total("/tasks", { project_uuid: p.uuid, due_date_before: soon }),
  ]);
}
writeFileSync("onboarding_health.csv", rows.map((r) => r.join(",")).join("\n"));
console.log("Wrote onboarding_health.csv");

Open onboarding_health.csv in Excel or Google Sheets, and you have your dashboard. Schedule the script to run every Monday and email the file, and your team gets a fresh health report in their inbox each week.

Make it yours
  • Change the "due soon" window — swap 7 days for 14 or 30 to match how far ahead your team plans.
  • Only want at-risk accounts? Keep just the rows where completion is low or overdue is above zero.
  • Add a "last active" column — call GET /v1/projects/{uuid}/activity?limit=1 per project to flag accounts that have gone quiet. (It's one extra call per project, so it's slower on large portfolios.)
Good to know
  • "Completed %" measures how many tasks are done — not how engaged the customer is. There's no portal-usage number in the API, so call it what it is.
  • Response shape. Every reply is {success, data, metadata}; list results sit at data.<resource> (e.g. data.projects) next to data.pagination (total, page, limit, previousPage, nextPagenextPage is null on the last page).
  • Counts are free and fast. Read data.pagination.total with limit=1 instead of downloading rows just to count them.
  • Statuses are objects. A project's status is {id, name} — display status.name.
  • Be kind to the API. You can make up to 600 read requests per minute. The full report is a couple of calls per project — fine for a few hundred accounts. Run it on a schedule (nightly or weekly) rather than in a tight loop.
  • Use UUIDs. Every example here uses the account's uuid. Older integer IDs are going away on July 31, 2026, so build with UUIDs from day one.