{"record":{"id":"b273269312173fb0","repo":"badges/shields","slug":"must-use-a-monitor-specific-api-key","errorCode":null,"errorMessage":"must use a monitor-specific api key","messagePattern":"must use a monitor-specific api key","errorType":"exception","errorClass":"InvalidParameter","httpStatus":null,"severity":"error","filePath":"services/uptimerobot/uptimerobot-base.js","lineNumber":45,"sourceCode":"    monitors: Joi.array().length(1).items(monitor).required(),\n  }).required(),\n)\n\nconst singleMonitorResponseWithUptime = Joi.alternatives(\n  errorResponse,\n  Joi.object({\n    stat: Joi.equal('ok').required(),\n    monitors: Joi.array().length(1).items(monitorWithUptime).required(),\n  }).required(),\n)\n\nexport default class UptimeRobotBase extends BaseJsonService {\n  static category = 'monitoring'\n\n  static ensureIsMonitorApiKey(value) {\n    // A monitor API key must start with \"m\".\n    if (!value.startsWith('m')) {\n      throw new InvalidParameter({\n        prettyMessage: 'must use a monitor-specific api key',\n      })\n    }\n  }\n\n  async fetch({ monitorSpecificKey, numberOfDays }) {\n    this.constructor.ensureIsMonitorApiKey(monitorSpecificKey)\n\n    let opts, schema\n    if (numberOfDays) {\n      opts = { custom_uptime_ratios: numberOfDays }\n      schema = singleMonitorResponseWithUptime\n    } else {\n      opts = {}\n      schema = singleMonitorResponse\n    }\n    const { stat, error, monitors } = await this._requestJson({\n      schema,","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/badges/shields/blob/766fd8bc89a90b8534dc573ab72dec30215ab1ec/services/uptimerobot/uptimerobot-base.js#L27-L63","documentation":"UptimeRobot's ensureIsMonitorApiKey throws InvalidParameter when the supplied key does not start with 'm'. UptimeRobot issues monitor-specific API keys prefixed with 'm' (e.g. m780550-...), while account-level keys look different; the badge requires the monitor-specific one. The check runs before the request in fetch().","triggerScenarios":"Any uptimerobot badge (e.g. response/uptime for a number of days) with a monitorSpecificKey that does not begin with the character 'm', including missing keys where startsWith throws implicitly.","commonSituations":"Using the main account API key instead of the per-monitor key; copying the monitor id rather than the monitor API key; the key losing its leading 'm' through trimming or template interpolation.","solutions":["In UptimeRobot, open the monitor's settings and copy the Monitor-specific API key (starts with 'm').","Replace the account-level main API key in the badge URL with the monitor-specific key.","Verify no string manipulation is stripping the leading 'm' from the key."],"exampleFix":"// before\n?apiKey=u695395-abc123...  (account key)\n// after\n?apiKey=m780550-def456...  (monitor-specific key)","handlingStrategy":"validation","validationCode":"if (!monitorSpecificKey || !monitorSpecificKey.startsWith('m')) throw new Error('monitor-specific API key (starting with m) required')","typeGuard":"const isMonitorKey = (v) => typeof v === 'string' && v.startsWith('m')","tryCatchPattern":"try { await fetchBadge() } catch (e) { if (e instanceof InvalidParameter) console.error('use the monitor-specific key'); throw e }","preventionTips":["Always use the per-monitor key (m-prefixed), never the account-level main key.","Store keys with their prefix intact; avoid regex/format transformations on keys.","Document in your badge config which key type each field expects."],"tags":["bad-request","api-key","validation"],"backgroundTag":"invalid-api-key","analyzedSha":"766fd8bc89a90b8534dc573ab72dec30215ab1ec","analyzedAt":"2026-08-30T01:40:27.499Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}