Red Dead Online's daily data, as JSON.
Madam Nazar's location, the daily challenges, the weekly set, lost jewelry and free roam events, for your Discord bot, app or website. Checked after every reset (06:00 UTC), so you never get yesterday's data.
Next reset in —Free key to start
Three steps
- Sign in to your madamnazar.io account and get a key (
mn_live_…): free, or Developer for every endpoint. - Send it in the
x-api-keyheader. - Read
locationfrom the JSON response.
Already have a key? Paste it in the console to run a real request.
curl https://developer.madamnazar.io/v1/location/today \
-H "x-api-key: $MADAM_NAZAR_KEY"
const res = await fetch("https://developer.madamnazar.io/v1/location/today", {
headers: { "x-api-key": process.env.MADAM_NAZAR_KEY },
});
const { location } = await res.json();
console.log(`Madam Nazar is in ${location.region}`);
import os, requests
res = requests.get(
"https://developer.madamnazar.io/v1/location/today",
headers={"x-api-key": os.environ["MADAM_NAZAR_KEY"]},
)
location = res.json()["location"]
print(f"Madam Nazar is in {location['region']}")
{
"date": "2026-10-26",
"location": {
"name": "point 8",
"region": "west elizabeth",
"cardinals": "south east",
"image": "https://madamnazar.github.io/images/location/rdo_map_nazar_8_btvqxe.jpg"
},
"attribution": "Data by MadamNazar.io — https://madamnazar.io",
"meta": {
"api_version": "v1",
"request_id": "01M5T8GK73WBWWM2C9JDRT08V1",
"requested_at": "2026-10-26T09:12:04.318Z",
"response_time_ms": 41,
"game_day": "2026-10-26",
"next_reset_at": "2026-10-27T06:00:00.000Z",
"valid_from": "2026-10-26T06:00:00.000Z",
"valid_until": "2026-10-27T06:00:00.000Z",
"location_updated_at": "2026-10-26T06:03:11.000Z",
"cache_ttl_seconds": 60,
"rate_limit": { "limit": 1000, "remaining": 999, "resets_at": "2026-10-27T00:00:00.000Z" },
"docs": "https://developer.madamnazar.io"
}
}
Authentication
Every request needs your API key. Send it in the x-api-key header. Authorization: Bearer and the ?api_key= query parameter also work, for tools that can't set custom headers.
Keep your key on your server or in your bot's environment variables. Anyone who has it can spend your quota. If it leaks, get a new one from your account: the old one stops working immediately.
Base URL: https://developer.madamnazar.io. All requests use HTTPS.
# Preferred
-H "x-api-key: mn_live_…"
# Also accepted
-H "Authorization: Bearer mn_live_…"
https://developer.madamnazar.io/v1/location/today?api_key=mn_live_…
Get today's location
Returns where Madam Nazar is right now. The location changes at the daily reset, 06:00 UTC. Until the new location is confirmed, usually a few minutes after the reset, you get a 503 with location_not_confirmed_yet and a Retry-After header: we never return yesterday's spot as today's.
Parameters
None.
Returns
A location object, an attribution string and a meta object with timing, validity window and quota.
curl https://developer.madamnazar.io/v1/location/today \
-H "x-api-key: $MADAM_NAZAR_KEY"
const res = await fetch("https://developer.madamnazar.io/v1/location/today", {
headers: { "x-api-key": process.env.MADAM_NAZAR_KEY },
});
const today = await res.json();
today = requests.get(
"https://developer.madamnazar.io/v1/location/today",
headers={"x-api-key": os.environ["MADAM_NAZAR_KEY"]},
).json()
{
"date": "2026-10-26",
"location": {
"name": "point 8",
"region": "west elizabeth",
"cardinals": "south east",
"image": "https://madamnazar.github.io/images/location/rdo_map_nazar_8_btvqxe.jpg"
},
"attribution": "Data by MadamNazar.io — https://madamnazar.io",
"meta": {
"api_version": "v1",
"request_id": "01M5T8GK73WBWWM2C9JDRT08V1",
"requested_at": "2026-10-26T09:12:04.318Z",
"response_time_ms": 41,
"game_day": "2026-10-26",
"next_reset_at": "2026-10-27T06:00:00.000Z",
"valid_from": "2026-10-26T06:00:00.000Z",
"valid_until": "2026-10-27T06:00:00.000Z",
"location_updated_at": "2026-10-26T06:03:11.000Z",
"cache_ttl_seconds": 60,
"rate_limit": { "limit": 1000, "remaining": 999, "resets_at": "2026-10-27T00:00:00.000Z" },
"docs": "https://developer.madamnazar.io"
}
}
List past locations
Returns recent locations, newest first, or the location for one given day.
Query parameters
How many days to return. Defaults to 7.
Return a single day instead of a list. Responds 404 no_location_for_date if that day isn't recorded.
Returns
With days: a data array of location objects and their count. With date: one location object. Both come with a meta object.
curl "https://developer.madamnazar.io/v1/location/history?days=2" \
-H "x-api-key: $MADAM_NAZAR_KEY"
const url = new URL("https://developer.madamnazar.io/v1/location/history");
url.searchParams.set("days", "2");
const { data } = await fetch(url, {
headers: { "x-api-key": process.env.MADAM_NAZAR_KEY },
}).then((r) => r.json());
data = requests.get(
"https://developer.madamnazar.io/v1/location/history",
params={"days": 2},
headers={"x-api-key": os.environ["MADAM_NAZAR_KEY"]},
).json()["data"]
{
"data": [
{
"date": "2026-10-26",
"location": { "name": "point 8", "region": "west elizabeth", "cardinals": "south east", "image": "…" }
},
{
"date": "2026-10-25",
"location": { "name": "point 11", "region": "new austin", "cardinals": "south east", "image": "…" }
}
],
"count": 2,
"attribution": "Data by MadamNazar.io — https://madamnazar.io",
"meta": {
"api_version": "v1",
"request_id": "01M5T9C2XH0K4W7QF8N3B6ZJ1D",
"requested_at": "2026-10-26T09:12:09.051Z",
"response_time_ms": 38,
"game_day": "2026-10-26",
"next_reset_at": "2026-10-27T06:00:00.000Z",
"rate_limit": { "limit": 1000, "remaining": 998, "resets_at": "2026-10-27T00:00:00.000Z" },
"docs": "https://developer.madamnazar.io"
}
}
Get today's daily challenges
The day's 7 general challenges and the role challenges, in three difficulty tiers. They change at the 06:00 UTC reset. Until the new ones are out, usually a few minutes later, you get a 503 with not_published_yet and a Retry-After header.
Parameters
None.
Returns
general: one challenge set. roles.easy, roles.medium, roles.hard: one set per role (bounty_hunter, trader, collector, moonshiner, naturalist). Each set has starts_at, ends_at and challenges: id (Rockstar id), goal and an English description.
Every response also has a date (the game day), a source, an attribution string and a meta object.
curl https://developer.madamnazar.io/v1/challenges/today \
-H "x-api-key: $MADAM_NAZAR_KEY"
{
"date": "2026-10-27",
"general": {
"role": "general",
"starts_at": "2026-10-27T06:00:00.000Z",
"ends_at": "2026-10-28T06:00:00.000Z",
"challenges": [
{ "id": "MPDC_AnimalsSkinned_Muskrat_00", "goal": 2, "description": "American Muskrats skinned" }
]
},
"roles": {
"easy": [
{
"role": "bounty_hunter",
"starts_at": "2026-10-27T06:00:00.000Z",
"ends_at": "2026-10-28T06:00:00.000Z",
"challenges": [
{ "id": "MPRC_Bounty_General_Delivered_Easy_00", "goal": 1, "description": "Bounty targets brought in" }
]
}
],
"medium": [ … ],
"hard": [ … ]
},
"source": { "name": "RDO Dailies", "url": "https://rdo-dailies.com" },
"attribution": "Data by MadamNazar.io — https://madamnazar.io",
"meta": { "game_day": "2026-10-27", "valid_from": "2026-10-27T06:00:00.000Z", "valid_until": "2026-10-28T06:00:00.000Z", "…": "…" }
}
Get the weekly collection set
The collection Madam Nazar buys this week, with its items and what she pays for it. It changes with the weekly update.
Parameters
None.
Returns
set: id, name, value (dollars), items (id and name) and game_id, the Rockstar award id.
Every response also has a date (the game day), a source, an attribution string and a meta object.
curl https://developer.madamnazar.io/v1/collector/weekly-set \
-H "x-api-key: $MADAM_NAZAR_KEY"
{
"date": "2026-10-27",
"set": {
"id": "set_saint_denis",
"name": "Saint Denis",
"value": 85,
"items": [
{ "id": "consumable_cognac", "name": "Cognac Bottle" },
{ "id": "provision_jewelry_rudy_dngl_earring", "name": "Beauchêne Ruby Earrings" },
{ "id": "provision_jewelry_french_dmnd_ring", "name": "French Diamond Ring" }
],
"game_id": "AWARD_ROLE_COLLECTOR_SET_SAINT_DENIS"
},
"source": { "name": "RDO Dailies", "url": "https://rdo-dailies.com" },
"attribution": "Data by MadamNazar.io — https://madamnazar.io",
"meta": { "game_day": "2026-10-27", "valid_from": "2026-10-27T06:00:00.000Z", "valid_until": "2026-10-28T06:00:00.000Z", "…": "…" }
}
List lost jewelry in static spots
Every lost jewelry item that can sit in a fixed spot on the map, and whether you can pick it up there right now.
Parameters
None.
Returns
items: id, name, available_until (null when the item isn't in its spot) and available, computed when you call. updated_at: when the list was last checked.
Every response also has a date (the game day), a source, an attribution string and a meta object.
curl https://developer.madamnazar.io/v1/collector/jewelry \
-H "x-api-key: $MADAM_NAZAR_KEY"
{
"date": "2026-10-27",
"updated_at": "2026-10-27T03:17:03.000Z",
"items": [
{ "id": "provision_jewelry_onyx_ring", "name": "Aubrey Onyx Ring", "available_until": "2026-10-30T06:00:00.000Z", "available": true },
{ "id": "provision_jewelry_emerald_ring", "name": "Emerald Ring", "available_until": null, "available": false }
],
"source": { "name": "RDO Dailies", "url": "https://rdo-dailies.com" },
"attribution": "Data by MadamNazar.io — https://madamnazar.io",
"meta": { "game_day": "2026-10-27", "valid_from": "2026-10-27T06:00:00.000Z", "valid_until": "2026-10-28T06:00:00.000Z", "…": "…" }
}
Get the free roam event schedule
The daily schedule of free roam events, in UTC, and the next general and role event from now.
Parameters
None.
Returns
general and role: events with time_utc (HH:MM), id, name and variation (for random challenges). next.general and next.role: the next event of each, with its starts_at.
Every response also has a date (the game day), a source (rdo.gg), an attribution string and a meta object.
curl https://developer.madamnazar.io/v1/events \
-H "x-api-key: $MADAM_NAZAR_KEY"
{
"date": "2026-10-27",
"general": [
{ "time_utc": "00:00", "id": "fme_cold_dead_hands", "name": "Cold Dead Hands", "variation": null },
{ "time_utc": "01:30", "id": "fme_challenges", "name": "Random Challenge", "variation": { "id": "fme_challenge_wild_animals_kills", "name": "Wild Animal Kills" } }
],
"role": [
{ "time_utc": "00:22", "id": "fme_role_protect_legendary_animal", "name": "Protect Legendary Animal", "variation": null }
],
"next": {
"general": { "time_utc": "09:45", "id": "fme_wildlife_photographer", "name": "Wildlife Photographer", "variation": null, "starts_at": "2026-10-27T09:45:00.000Z" },
"role": { "time_utc": "10:52", "id": "fme_role_manhunt", "name": "Manhunt", "variation": null, "starts_at": "2026-10-27T10:52:00.000Z" }
},
"source": { "name": "rdo.gg", "url": "https://rdo.gg" },
"attribution": "Data by MadamNazar.io — https://madamnazar.io",
"meta": { "game_day": "2026-10-27", "valid_from": "2026-10-27T06:00:00.000Z", "valid_until": "2026-10-28T06:00:00.000Z", "…": "…" }
}
The location object
Game day the location is valid for (UTC, YYYY-MM-DD).
Spot name, for example point 8.
Map region, for example new austin.
Position within the region, for example south east.
URL of a map image you can display.
{
"date": "2026-10-26",
"location": {
"name": "point 8",
"region": "west elizabeth",
"cardinals": "south east",
"image": "https://madamnazar.github.io/images/location/rdo_map_nazar_8_btvqxe.jpg"
}
}
The meta object
Every response, errors included, ends with a meta object. Use it to time your requests, know when to fetch again, and track your quota without reading headers.
API version that answered, currently v1.
Unique id of this request, also sent in the X-Request-Id header. Include it when you report a problem.
When the server received your request (ISO 8601, UTC).
Time the server took to answer, in milliseconds.
Current game day (YYYY-MM-DD). It starts at the 06:00 UTC reset.
Next daily reset, when Madam Nazar moves (ISO 8601, UTC).
Window during which the returned data is valid: one game day. Single-day responses only (one location, or the daily data endpoints).
When we recorded this location. Single-location responses only.
When we fetched this data. Daily data endpoints only.
How long you can safely cache the response. Single-day responses only.
limit, remaining and resets_at (next 00:00 UTC) for your key. Missing on 401 errors, before the key is known.
Link to this documentation.
{
"meta": {
"api_version": "v1",
"request_id": "01M5T8GK73WBWWM2C9JDRT08V1",
"requested_at": "2026-10-26T09:12:04.318Z",
"response_time_ms": 41,
"game_day": "2026-10-26",
"next_reset_at": "2026-10-27T06:00:00.000Z",
"valid_from": "2026-10-26T06:00:00.000Z",
"valid_until": "2026-10-27T06:00:00.000Z",
"location_updated_at": "2026-10-26T06:03:11.000Z",
"cache_ttl_seconds": 60,
"rate_limit": { "limit": 1000, "remaining": 999, "resets_at": "2026-10-27T00:00:00.000Z" },
"docs": "https://developer.madamnazar.io"
}
}
Rate limits
Each key can make 1,000 requests per UTC day. The counter resets at 00:00 UTC. Every response tells you where you stand, in the headers and in meta.rate_limit.
The location changes once a day, so cache it on your side for a few minutes: a bot that asks once every 5 minutes uses fewer than 300 requests a day.
Need more? Write to me.
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 742
X-RateLimit-Reset: 1793059200 # next 00:00 UTC, Unix seconds
X-Request-Id: 01M5T8GK73WBWWM2C9JDRT08V1
Errors
Errors use standard HTTP status codes and a JSON body with a stable error code and a readable message. The full contract is in the OpenAPI specification.
| Status | error | Meaning |
|---|---|---|
| 401 | missing_api_key | No key was sent. |
| 401 | invalid_api_key | Unknown or replaced key. |
| 403 | subscription_inactive | The subscription was canceled or isn't paid. |
| 403 | plan_upgrade_required | Free keys only reach /v1/location/today. |
| 404 | no_location_for_date | No record for that date. |
| 429 | rate_limited | Daily limit reached. |
| 503 | location_not_confirmed_yet | Just after the 06:00 UTC reset, before today's location is confirmed. Retry after the Retry-After delay. |
| 503 | location_unavailable | Try again in a few minutes. |
| 503 | not_published_yet | Daily data endpoints, just after the 06:00 UTC reset. Retry after the Retry-After delay. |
| 503 | data_unavailable | Daily data endpoints: the data can't be fetched right now. Retry after the Retry-After delay. |
{
"error": "rate_limited",
"message": "Daily limit of 1000 requests reached (resets at 00:00 UTC)."
}
Guide: a Discord bot
A /nazar slash command that answers with today's location and its map, using discord.js.
Put your key in the MADAM_NAZAR_KEY environment variable, next to your bot token. Cache the answer: the location only changes once a day.
import { Client, EmbedBuilder, GatewayIntentBits } from "discord.js";
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
let cache = { at: 0, body: null };
async function getToday() {
if (Date.now() - cache.at < 5 * 60 * 1000) return cache.body;
const res = await fetch("https://developer.madamnazar.io/v1/location/today", {
headers: { "x-api-key": process.env.MADAM_NAZAR_KEY },
});
cache = { at: Date.now(), body: await res.json() };
return cache.body;
}
client.on("interactionCreate", async (interaction) => {
if (!interaction.isChatInputCommand() || interaction.commandName !== "nazar") return;
const { location, attribution } = await getToday();
const embed = new EmbedBuilder()
.setTitle(`Madam Nazar is in ${location.region}`)
.setDescription(`${location.name} (${location.cardinals})`)
.setImage(location.image)
.setFooter({ text: attribution });
await interaction.reply({ embeds: [embed] });
});
client.login(process.env.DISCORD_TOKEN);
Attribution
Wherever you show the data, display "Data by MadamNazar.io" with a link to madamnazar.io. Every response includes the exact text in attribution.
The daily data endpoints also name where the data comes from in source (RDO Dailies or rdo.gg). Credit it next to ours.
Migrating from Heroku
The old madam-nazar-location-api.herokuapp.com/location/current endpoint is now private. Call /v1/location/today instead, with your key in the x-api-key header. The response is flatter: map the old fields like this.
Heroku (/location/current) | v1 (/v1/location/today) |
|---|---|
dataFor / valid_for | date |
data.name | location.name |
data.location.region.name | location.region |
data.location.cardinals.full | location.cardinals |
data.location.image | location.image |
meta.execution_time | meta.response_time_ms (a number) |
meta.requested_at | meta.requested_at |
data.location.region.precise, near_by, cardinals.simplified and the collector cycle aren't in v1. If you need them, tell me.
Two behaviours changed. Just after the 06:00 UTC reset, v1 answers 503 location_not_confirmed_yet with a Retry-After header instead of returning yesterday's spot. And each key has a daily quota.
// Before: public endpoint, now private
const old = await fetch("https://madam-nazar-location-api.herokuapp.com/location/current")
.then((r) => r.json());
const region = old.data.location.region.name;
// After
const res = await fetch("https://developer.madamnazar.io/v1/location/today", {
headers: { "x-api-key": process.env.MADAM_NAZAR_KEY },
});
if (res.status === 503) {
// Reset just happened: retry after Retry-After seconds
}
const { date, location, meta } = await res.json();
console.log(location.region, location.cardinals, meta.valid_until);
Pricing
Keys live in your madamnazar.io account: sign in, then get a free key or subscribe. Commercial use allowed. Cancel any time from your account.
- 1,000 requests a day
- Today + 30 days of history
- Daily challenges, weekly set, jewelry, events
- Email support
- Everything in monthly
- One payment a year
- About 4 months free vs monthly
Secure payment by Stripe. Non-commercial project or need more requests? Write to me.
# In your account
Your API key: mn_live_••••••••••••••••••••••••
Plan: Developer
Quota: 1000 requests / day
Endpoints: /v1/location/today
/v1/location/history
/v1/challenges/today
/v1/collector/weekly-set
/v1/collector/jewelry
/v1/events