On this page
Overview
The API gives your code what a scan gives you in the app: the businesses of an area with their opportunity scores, a read of a website, and drafts and reports from RadiusPilot AI. It takes and answers JSON, over HTTPS, at one address:
https://radiuspilot.com/api/v1/| Who | Accepted beta testers. Request access |
|---|---|
| Credits | 50 to try it, from the same balance as the app |
| Limits | 30 requests a minute and 1,000 a day, per key |
| Version | v1, in the address |
Get a key
Join the beta
Request access on the beta page. An accepted request comes with a beta code.
Create a key
Sign in to your account, open API and choose Create key. Name it after where it will run. The first time, paste your beta code.
Copy it once
The key is shown once. Keep it in your server’s secrets or a password manager: we store only a hash of it and its first 12 characters, so we can’t show it again.
Revoke it any time
On the same page. It stops working at once, and the apps using it with it.
Authentication
Send your key in the Authorization header of every request. Keys start with rp_live_, then 32 random characters.
Authorization: Bearer rp_live_…A missing, mistyped or revoked key gets 401 unauthorized. Every answer carries an X-Request-Id header: quote it when you write to us about a request.
Credits
Requests spend credits from your account’s balance, the same credits as in the app. A success says what it used and what’s left, in credits:
"credits": { "used": 10, "left": 40 }| Endpoint | Credits |
|---|---|
GET /v1/account | 0 |
POST /v1/businesses/search | 10 |
POST /v1/sites/check | 1 |
POST /v1/ai/write | 1 |
POST /v1/ai/report | 3 |
- A request that fails gives its credits back: a server error, or a service behind it that doesn’t answer.
- Without enough credits, a request answers
402 not_enough_creditsand spends nothing. Nothing is ever charged automatically. - What each action costs in the app, and the credit packs, are on the pricing page.
Endpoints
Five endpoints in v1. Paths are relative to the base URL. Requests with a body send JSON with Content-Type: application/json.
GET/v1/accountNo credits
The key and its balance. Which key is calling, the credits left on the account and the key’s limits. A good first call to check that a key works.
curl https://radiuspilot.com/api/v1/account \
-H "Authorization: Bearer $RADIUSPILOT_API_KEY"{
"key": {
"prefix": "rp_live_7Hq2",
"name": "Agency CRM",
"created_at": "2026-11-03T14:02:11Z"
},
"credits": {
"left": 50,
"granted": 50
},
"limits": {
"per_minute": 30,
"per_day": 1000
}
}POST/v1/businesses/search10 credits
Businesses in an area, scored. Every named business of the kinds you ask for around a point, nearest first, each with its opportunity score from 0 to 100 and the reasons behind it: the same facts and weights as a scan in the app.
| Body | Type | What it is |
|---|---|---|
lat | number | Required. Latitude of the centre, like 45.5231 |
lng | number | Required. Longitude of the centre, like -73.5817 |
radius_m | integer | Required. The radius in metres, from 100 to 5,000 |
categories | string[] | Optional. Kinds of businesses: dentist, restaurant, cafe, gym, salon, spa, auto, plumber, hvac, roofing, law, realestate, vet, clinic, chiro, bakery, retail, hotel. Leave it out for all 18 |
limit | integer | Optional. At most 500 businesses |
curl -X POST https://radiuspilot.com/api/v1/businesses/search \
-H "Authorization: Bearer $RADIUSPILOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"lat":45.5231,"lng":-73.5817,"radius_m":1500,"categories":["dentist"],"limit":100}'{
"businesses": [
{
"id": "b_4815162342",
"name": "Cedar Smile Dental",
"category": "dentist",
"lat": 45.5243,
"lng": -73.5794,
"address": "4120 Rue Saint-Denis, Montréal",
"phone": "+1 514-555-0142",
"website": null,
"has_website": false,
"score": 78,
"level": "high",
"reasons": [
"No website on its listing",
"No opening hours on its listing"
]
}
],
"attribution": "© OpenStreetMap contributors (ODbL)",
"credits": {
"used": 10,
"left": 40
}
}| In the answer | Type | What it is |
|---|---|---|
score | integer | 0 to 100: the higher, the more the business is missing that an agency can fix |
level | string | "high" (60 and up), "medium" (40 to 59) or "low" |
reasons | string[] | What the score is built from, in words |
attribution | string | The data licence’s credit: show it with the data (below) |
POST/v1/sites/check1 credit
Check a website. One ordinary request for a homepage, as a browser makes it: where it lands, whether it loads over HTTPS and fits a phone, its title and description, online booking, the technology behind it and its social links.
| Body | Type | What it is |
|---|---|---|
url | string | Required. The website, like https://maplefitness.example.com |
curl -X POST https://radiuspilot.com/api/v1/sites/check \
-H "Authorization: Bearer $RADIUSPILOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://maplefitness.example.com"}'{
"site": {
"url": "https://maplefitness.example.com",
"final_url": "https://www.maplefitness.example.com/",
"status": 200,
"https": true,
"title": "Maple Fitness · Small-group training in Verdun",
"description": "Classes and personal training, six days a week.",
"mobile_viewport": true,
"booking": false,
"booking_provider": null,
"technology": [
"WordPress"
],
"social": []
},
"credits": {
"used": 1,
"left": 39
}
}POST/v1/ai/write1 credit
Draft an email or a message. RadiusPilot AI drafts a first email, a follow-up or a short message to a business, from the facts you give it. It writes; it never sends.
| Body | Type | What it is |
|---|---|---|
business | object | Required. name, and optionally category, city and facts (short sentences it may use) |
kind | string | Required. "email", "follow_up" or "message" |
language | string | Optional. A language code, like "en" or "fr" |
notes | string | Optional. What you sell, the tone, what to mention |
curl -X POST https://radiuspilot.com/api/v1/ai/write \
-H "Authorization: Bearer $RADIUSPILOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"business":{"name":"Cedar Smile Dental","category":"dentist","city":"Montréal","facts":["No website on its listing","Open six days a week"]},"kind":"email","language":"en","notes":"We build websites for dental clinics."}'{
"draft": {
"subject": "A website for Cedar Smile Dental",
"body": "Hello,\n\nI noticed Cedar Smile Dental doesn’t list a website yet. Patients searching nearby…"
},
"credits": {
"used": 1,
"left": 38
}
}POST/v1/ai/report3 credits
Write a report. RadiusPilot AI writes a short report in Markdown: a website review from its URL, or a business’s situation from the facts you send.
| Body | Type | What it is |
|---|---|---|
business | object | Optional. As for ai/write |
url | string | Optional. A website to review |
facts | string[] | Optional. Facts to build on |
language | string | Optional. A language code, like "en" or "fr" |
curl -X POST https://radiuspilot.com/api/v1/ai/report \
-H "Authorization: Bearer $RADIUSPILOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://maplefitness.example.com","language":"en"}'{
"report": {
"markdown": "# Maple Fitness: website review\n\n## What works\n…"
},
"credits": {
"used": 3,
"left": 35
}
}Errors
An error has an HTTP status and a body with a short code to test against and a message to read:
{
"error": {
"code": "not_enough_credits",
"message": "This request needs 10 credits, and 4 are left."
}
}| Status | Code | What happened |
|---|---|---|
| 400 | invalid_request | A field is missing, has the wrong type or is out of range |
| 401 | unauthorized | No key, a mistyped key or a revoked one |
| 402 | not_enough_credits | The request needs more credits than are left. Nothing is spent |
| 403 | beta_only | The account isn’t an accepted beta tester yet |
| 404 | not_found | No such endpoint |
| 429 | rate_limited | Over the key’s limit. Retry-After says how many seconds to wait |
| 502 | upstream_failed | A service behind the request didn’t answer. Its credits are given back |
| 503 | server_busy | A daily limit on our side is reached. Try again later |
| 503 | not_configured | That part of the API isn’t switched on yet |
Limits
- 30 requests a minute and 1,000 a day, per key. Past either one:
429 rate_limited, withRetry-Afterin seconds. - RadiusPilot AI keeps its own daily limits on our server. When one is reached,
ai/writeandai/reportanswer503 server_busyuntil later. - During the beta, business searches also share a daily cap across every key. Past it,
businesses/searchanswers503 server_busy. - Credits a busy or failed request didn’t use stay on your balance.
What it never returns
- Google data. Google’s terms don’t allow passing it on, so Verify listing stays in the app.
- Email addresses. Collecting addresses in bulk with software goes against Canada’s anti-spam and privacy laws, so the API never does it.
- What a site hides from robots. A site check reads the homepage as a visitor sees it, and never decodes a hidden address.
- Ratings, reviews or rankings. Public listings don’t have them, and RadiusPilot never makes them up.
The data licence
Business data comes from public listings shared under an open licence, which asks for a credit wherever the data is shown. Every search answer carries it in attribution. Show it next to the data, as RadiusPilot’s exported reports do.
"attribution": "© OpenStreetMap contributors (ODbL)"Drafts and anti-spam law
ai/write writes a draft. It never sends anything, and what you send is up to you:
- Email a business only with its consent, express or implied, as Canada’s anti-spam law (CASL) asks for email received in Canada.
- Add your business name, your postal address and a working way to unsubscribe. RadiusPilot’s own outreach adds them for you; a draft from the API doesn’t.
- Read it before it goes out: it’s AI-generated and can be wrong.
See Email rules and the CASL guide. Not legal advice.
