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:
| project | status | completed_% | overdue | due_soon |
|---|---|---|---|---|
| Acme Health rollout | In Progress | 72 | 1 | 3 |
| Globex onboarding | In Progress | 45 | 4 | 2 |
| Initech data migration | On Track | 88 | 0 | 1 |
| Umbrella Corp setup | At Risk | 23 | 6 | 5 |
| Wayne Enterprises portal | On Track | 95 | 0 | 0 |
| Stark Industries kickoff | In Progress | 61 | 2 | 4 |
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=1per 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 atdata.<resource>(e.g.data.projects) next todata.pagination(total,page,limit,previousPage,nextPage—nextPageis null on the last page). - Counts are free and fast. Read
data.pagination.totalwithlimit=1instead of downloading rows just to count them. - Statuses are objects. A project's
statusis{id, name}— displaystatus.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.