No-Spec Vendor JSON API Response Drift Watcher
Pricing
from $20.00 / 1,000 run starteds
No-Spec Vendor JSON API Response Drift Watcher
Watch public JSON GET endpoints for response-shape drift without an OpenAPI spec. The Actor learns the shape from the response, compares it against a stored baseline, and reports each field-level change with a breaking flag.
Pricing
from $20.00 / 1,000 run starteds
Rating
0.0
(0)
Developer
kingii98
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
Watch public JSON GET endpoints of a third party for response-shape drift without an OpenAPI
spec and without authentication.
The Actor sends one plain GET to each endpoint, learns the response shape from the body, and
compares that shape against a baseline that it keeps between runs. It reports each field-level
change with a JSON path, a change class, and a breaking flag. The first run creates the baseline
and reports no drift.
Who this is for
The integration engineer whose product calls the public JSON endpoints of a vendor, who has no OpenAPI file for those endpoints, and who does not want to add authentication to a monitor.
What the Actor does
- Fetches each endpoint with one
GET. No browser, no proxy, no authentication, no paid API. - Infers the shape: every field gets a JSON pointer, a set of types, a nullable flag, and, when the field is a small repeated string set, an enum.
- Loads the baseline from the named key-value store
json-api-shape-baseline. - Diffs the new shape against the baseline and marks each change breaking or not.
- Writes one dataset record for each endpoint, one summary record, and the new baseline.
Input
Every field has a default, so a run with an empty input {} works.
| Field | Type | Default | Meaning |
|---|---|---|---|
endpoints | array of URL strings | two public demo endpoints | 1 to 25 public JSON GET URLs. No authentication. |
baselineStore | string | SHAPE_BASELINE | Record key of the shape baseline in the named store json-api-shape-baseline. |
ignorePaths | array of JSON pointers | [] | Pointers to ignore, for example /meta/timestamp. A pointer also ignores everything below it. |
sampleDepth | integer 1–12 | 6 | Maximum object depth for shape inference. |
arraySampleSize | integer 1–200 | 20 | Maximum number of elements read from each array. |
breakingRules | array of change classes | ["removed", "type-changed", "nullability-changed"] | Which change classes count as breaking. |
concurrency | integer 1–25 | 5 | Endpoints fetched at the same time. |
timeoutSecs | integer 2–120 | 20 | Per-request timeout. |
maxRedirects | integer 0–20 | 5 | Redirect hops followed. Every hop is checked again. |
maxResponseBytes | integer 1000–5000000 | 5000000 | Per-endpoint body cap. |
JSON pointers
A pointer names one field, for example /data/user/id. All elements of one array share the token
-, so /items/-/price is the price field of any element of items. ~1 stands for / inside
a key, and ~0 stands for ~.
Change classes
| Class | Meaning | Breaking by default |
|---|---|---|
added | A field that the baseline does not have. | No |
removed | A field of the baseline that the response no longer has. | Yes |
type-changed | The type set of the field changed, for example integer to string. | Yes |
nullability-changed | The field started, or stopped, being null. | Only when it started being null |
enum-changed | The inferred small string set of the field changed. | No |
A field becomes an enum only when it is seen at least 3 times, is always a string, has at most 12 distinct values, and each value is at most 64 characters. This keeps free-form text out of the enum diff.
Output
The dataset holds one summary record and one endpoint record for each endpoint.
endpoint record: url, finalUrl, ok, reasonCode, httpStatus, bytesRead,
responseTimeMs, shapeHash, baselineShapeHash, baselineStatus (created, compared or
unavailable), fieldCount, shapeTruncated, changeCount, breakingCount, diffTruncated,
diff, error, checkedAt. Each diff item has path, changeClass, from, to and
breaking.
summary record: endpointsRequested, endpointsChecked, endpointsFailed, baselinesCreated,
endpointsCompared, endpointsWithDrift, changeCount, breakingCount, changeCounts,
gatePass, gateFailReasons, baselineStore, baselineKey, checkedAt.
gatePass is false when the run found a breaking change (BREAKING_CHANGE) or could not read an
endpoint (ENDPOINT_UNAVAILABLE).
Reason codes
OK, HTTP_ERROR, NOT_JSON, RESPONSE_TOO_LARGE, TIMEOUT, DNS_FAIL, CONNECT_FAIL,
BLOCKED_TARGET, REDIRECT_LOOP.
The run always succeeds
Drift, a failed gate, an unreachable endpoint and a body that is not JSON are results, not
faults. They go into the dataset and into the run status message, and the run ends SUCCEEDED.
A FAILED run means a real malfunction.
State between runs
The baseline lives in the named key-value store json-api-shape-baseline, under the record key
that baselineStore gives. A named store outlives the run; the default store of a run does not.
The record is written once, at the end of the run, so an aborted run leaves the previous baseline
intact. An endpoint that the run could not read keeps its stored baseline.
The record holds at most 200 endpoints, and each endpoint shape holds at most 2000 fields.
Schedule it
The value of a baseline grows with the number of comparisons. Run the Actor on a schedule, for
example every hour or every day, against the same baselineStore key.
Pricing (pay per event)
| Event | Unit | Counted as |
|---|---|---|
run-started | one Actor run | Charged once for each run, before any endpoint is fetched. It pays for the container start and the summary write. |
endpoint-checked | one endpoint fetched and shape-compared | Charged once for each endpoint whose body was read and whose shape was inferred. An endpoint that timed out, was blocked, or did not answer JSON is not charged. |
drift-report-emitted | one endpoint with one or more changes | Charged once for each checked endpoint whose diff has at least one item. |
The run never checks more endpoints than its maximum charge allows. When the limit covers fewer endpoints than the input asks for, the Actor logs a warning, checks the endpoints it can pay for, and leaves the baseline of the others as it is.
Safety limits
GETonly,httpandhttpsonly.- URLs with credentials,
localhosttargets, and hosts that resolve to a private or reserved address are rejected. Each redirect hop is checked again. - Bounded input (25 endpoints, 50 ignore paths), concurrency, redirects, response bytes, timeout, shape fields (2000), diff items (200), and baseline entries (200).
Development
uv syncuv run pytestuv run ruff check .