Developer API
Authenticate, list monitors, fetch incidents, and stream check results from Pingara programmatically using the v1 REST Developer API.
The Pingara Developer API gives you programmatic access to your monitors, incidents, and check results over HTTPS. It's designed for CI/CD pipelines, internal dashboards, ChatOps tools, and any other system that needs to read monitoring state without screen-scraping the UI.
At a glance
- Base URL (production):
https://api.pingara.io/api/v1 - Base URL (development):
https://api-dev.pingara.io/api/v1 - Auth: Bearer token (
Authorization: Bearer pgr_…) - Format: JSON, UTF-8
- Scope: v1 is read-only and scoped to a single organization per key
- Rate limit: 600 requests per minute, per key
- Versioning: All endpoints live under
/api/v1. Breaking changes ship under/api/v2.
1. Create an API key
- Sign in to Pingara and switch to the organization you want to script against.
- Open Settings → API.
- Click Create key, give it a recognisable name (for example
CI deployorGrafana sync), and submit. - Copy the full key immediately. It is shown exactly once and starts with the prefix
pgr_. Pingara only stores a SHA-256 hash, so a lost key cannot be recovered — revoke it and create a new one.
Only owners and admins can create or revoke keys. Each organization can hold up to 25 active keys at a time.
Storing keys safely
- Treat the key like a password. Anyone with it can read every monitor, incident, and check result in your organization.
- Store keys in your secrets manager (1Password, Vault, AWS Secrets Manager, GitHub Actions secrets, etc.) — never in source control.
- Use a dedicated key per integration so you can revoke one without breaking the rest.
2. Authentication
Every request must include an Authorization header:
curl https://api.pingara.io/api/v1/me \
-H "Authorization: Bearer pgr_abcdef0123456789..."
Successful responses return JSON with HTTP 200. Authentication failures
return 401:
{ "error": "Invalid or revoked API key" }
3. Resources
GET /api/v1/me
Returns metadata about the organization the key belongs to.
{
"organization": {
"id": "j5k2…",
"name": "Acme Inc",
"slug": "acme",
"plan": "pro"
},
"apiKey": {
"id": "abcd…",
"scopes": ["read"]
}
}
Useful as a health-check at the start of a CI job.
GET /api/v1/monitors
List monitors in the organization, most recently updated first.
| Query param | Type | Description |
|---|---|---|
limit | integer (1–200) | Maximum monitors to return. Default 50. |
status | string | Filter to one of up, down, degraded, pending, paused. |
Example response:
{
"count": 2,
"data": [
{
"id": "m1aa…",
"name": "Marketing site",
"url": "https://www.example.com",
"type": "http",
"method": "GET",
"interval": "1m",
"timeout": 10000,
"regions": ["us-east-1", "eu-west-1"],
"expectedStatusCodes": [200, 301, 302],
"keywordCheck": null,
"keywordCheckEnabled": false,
"apdexThreshold": 500,
"tags": ["public", "marketing"],
"environment": "production",
"status": "up",
"isEnabled": true,
"isPaused": false,
"lastCheckedAt": "2026-05-14T16:24:09.123Z",
"lastStatusChange": "2026-05-12T09:11:02.000Z",
"createdAt": "2026-01-04T12:00:00.000Z",
"updatedAt": "2026-05-14T16:24:09.123Z"
}
]
}
GET /api/v1/monitors/{id}
Returns a single monitor. Responds with 404 if the monitor does not exist
or belongs to a different organization.
GET /api/v1/monitors/{id}/checks
Most recent check results for a monitor (newest first).
| Query param | Type | Description |
|---|---|---|
limit | integer (1–200) | Default 50. |
Each result includes the regional probe, the timing breakdown (DNS / TCP / TLS / TTFB / total), response size, status code, and any error type/message.
GET /api/v1/monitors/{id}/incidents
Recent incidents for a single monitor, newest first.
GET /api/v1/incidents
Recent incidents across the whole organization.
| Query param | Type | Description |
|---|---|---|
limit | integer (1–200) | Default 50. |
status | string | Filter to investigating, identified, monitoring, or resolved. |
GET /api/v1/incidents/{id}
Returns a single incident with start/resolve timestamps, the affected regions, error metadata, and the AI-generated root-cause hint (when available).
4. Conventions
Response envelope
List endpoints return:
{ "data": [ ... ], "count": <number> }
Single-resource endpoints return:
{ "data": { ... } }
Timestamps
All timestamps are ISO 8601 strings in UTC, for example
"2026-05-14T16:24:09.123Z".
Errors
Errors use standard HTTP status codes plus a JSON body:
| Status | Meaning |
|---|---|
400 | Bad request — invalid query parameter |
401 | Missing, malformed, or revoked API key |
404 | Resource not found (or not in your organization) |
429 | Rate limit exceeded — see Retry-After header |
5xx | Server error — retry with exponential backoff |
Rate limiting
Each API key may make up to 600 requests per minute. When you exceed the
limit, the API returns 429 Too Many Requests with a Retry-After: 60
header. Build clients that respect both — a small fixed delay or
exponential backoff works well.
CORS
The Developer API responds to cross-origin requests from any origin and
supports preflight OPTIONS for the Authorization and Content-Type
headers, so you can call it directly from browser-based dashboards if you're
comfortable exposing the key (in general you should proxy through your
backend instead).
5. Examples
curl: list every down monitor
curl -sS "https://api.pingara.io/api/v1/monitors?status=down" \
-H "Authorization: Bearer $PINGARA_API_KEY" | jq '.data[].name'
Node.js / TypeScript
const base = process.env.PINGARA_API_BASE!; // https://api.pingara.io/api/v1
const key = process.env.PINGARA_API_KEY!;
async function listOpenIncidents() {
const res = await fetch(`${base}/incidents?status=investigating&limit=100`, {
headers: { Authorization: `Bearer ${key}` },
});
if (!res.ok) throw new Error(`Pingara API ${res.status}: ${await res.text()}`);
const body = (await res.json()) as { data: Array<{ id: string; monitorId: string; startedAt: string }> };
return body.data;
}
Python
import os, requests
base = os.environ["PINGARA_API_BASE"]
key = os.environ["PINGARA_API_KEY"]
resp = requests.get(
f"{base}/monitors",
headers={"Authorization": f"Bearer {key}"},
params={"limit": 200},
timeout=15,
)
resp.raise_for_status()
for m in resp.json()["data"]:
print(m["status"], m["name"], m["url"])
GitHub Actions deploy gate
- name: Block deploy if any monitor is down
env:
PINGARA_API_KEY: ${{ secrets.PINGARA_API_KEY }}
run: |
count=$(curl -sS \
"$PINGARA_API_BASE/monitors?status=down" \
-H "Authorization: Bearer $PINGARA_API_KEY" | jq '.count')
if [ "$count" -gt 0 ]; then
echo "::error::$count monitors currently down — aborting deploy"
exit 1
fi
6. Versioning & deprecation policy
- The v1 surface is stable. We will not remove fields or change types without bumping the major version.
- Additive changes (new fields on existing responses, new endpoints, new query parameters with safe defaults) ship under v1 and do not constitute a breaking change.
- When v2 ships, v1 will continue to operate for at least 12 months after the v2 GA announcement.
7. What's next
Roadmap items we're tracking for upcoming releases:
- Write endpoints (create / pause / resume monitors, acknowledge incidents)
- Scoped keys (read-only vs. write-only, per-monitor scopes)
- Webhook event subscriptions (push delivery of
incident.opened,incident.resolved,monitor.status_changed) - OpenAPI 3.1 spec for code generation
- SDKs for Node.js, Go, and Python
Have feedback or a use case we haven't covered? Email support@pingara.io — we'd love to hear from you.