API documentation

Base URL https://grid.jipidy.com · authenticate with the X-API-Key header (find your key on the dashboard).

POST /api/shot — screenshot matrix

Renders a URL on every requested device. Full-page screenshot, console errors, load time, title and a visual-regression diff per device.

curl -X POST https://grid.jipidy.com/api/shot \
  -H "X-API-Key: $JIPIDY_KEY" -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-site.com",
    "devices": ["desktop", "iphone-14"],       // optional, default: 6-device grid
    "diffThreshold": 0.1,                      // optional, % of pixels; 0 = strictest
    "auth": {                                  // optional, for protected apps — see Auth
      "headers": {"Authorization": "Bearer ..."}
    }
  }'
FieldTypeNotes
urlstring, requiredpublic http(s) URL — private/internal IPs are rejected
devicesstring[]desktop laptop iphone-14 iphone-se pixel-7 ipad galaxy-s9 safari iphone-14-safari ipad-safari firefox
diffThresholdnumberdiff "changed" cutoff in % of pixels (default 0.1)
authobjectheaders / basic / cookies — see Auth section

POST /api/flow — scripted journeys

Runs a sequence of steps on every device. Named screenshot steps become visual-regression checkpoints. Returns HTTP 422 if any device fails — CI can just use curl -f.

curl -f -X POST https://grid.jipidy.com/api/flow \
  -H "X-API-Key: $JIPIDY_KEY" -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-site.com/en/ski-rental",
    "devices": ["desktop", "iphone-14"],
    "video": true,                             // optional: webm replay per device
    "steps": [
      {"fill":    {"selector": "#location", "value": "Saalbach"}},
      {"click":   {"text": "SAALBACH"}},
      {"waitFor": {"selector": "#shop-list", "timeout": 10000}},
      {"screenshot": "shop-list"},
      {"click":   {"selector": "#shop-4675 [data-testid=proceedToShopLink]"}},
      {"assertVisible": {"selector": "[data-testid=productGrid]"}},
      {"screenshot": "products"}
    ]
  }'
VerbArgumentsDoes
gotourl stringnavigate (same SSRF rules as the start URL)
click{selector} or {text}click first match
fill{selector, value}fill input
presskey string, e.g. "Enter"keyboard press
select{selector, value}select option
waitFor{selector, state?, timeout?}wait for element (visible by default)
scrollTo{selector}scroll element into view
assertVisible{selector}fail step if not visible
assertText{selector, text}fail step if text not contained
screenshotlabel stringfull-page checkpoint + baseline diff

Limits: 30 steps, per-step timeout ≤ 30 s, 120 s per device. Failed step ⇒ step log + failure screenshot + console errors in the response.

Auth — testing apps behind a wall

All three can be combined. Secrets are used for the run and never stored — not in the database, not in run history.

"auth": {
  "headers": {"Authorization": "Bearer eyJ...", "X-Preview-Token": "abc"},   // ≤10 headers
  "basic":   {"username": "staging", "password": "hunter2"},                 // HTTP basic auth
  "cookies": [{"name": "session", "value": "s3cr3t", "domain": ".your-site.com"}]
}

Saved flows — schedules & webhook alerts

Save a journey once, then re-run it by id, put it on a schedule, and get webhook alerts when it breaks or the UI changes. This is how you turn Jipidy into continuous monitoring for your site.

# save (upsert by name)
curl -X POST https://grid.jipidy.com/api/flows \
  -H "X-API-Key: $JIPIDY_KEY" -H "Content-Type: application/json" \
  -d '{
    "name": "booking-journey",
    "url": "https://your-site.com/en/ski-rental",
    "devices": ["desktop", "iphone-14"],
    "video": true,
    "scheduleMinutes": 60,                      // run hourly (min 15; 0 = manual only)
    "webhook": "https://hooks.slack.com/...",   // POSTed on failure or visual change
    "auth": {"headers": {"X-Preview-Token": "abc"}},   // stored AES-256-GCM encrypted
    "steps": [ {"waitFor": {"selector": "#app"}}, {"screenshot": "home"} ]
  }'

curl https://grid.jipidy.com/api/flows -H "X-API-Key: $JIPIDY_KEY"          # list
curl -X POST https://grid.jipidy.com/api/flows/ID/run -H "X-API-Key: ..."  # run + wait for result
curl -X DELETE https://grid.jipidy.com/api/flows/ID -H "X-API-Key: ..."    # delete

# fire-and-forget: dispatch returns 202 immediately, then poll
curl -X POST https://grid.jipidy.com/api/flows/ID/dispatch -H "X-API-Key: ..."
# -> {"run": "9f2c1b...", "status": "queued", "poll": "https://grid.jipidy.com/api/runs/9f2c1b..."}
curl https://grid.jipidy.com/api/runs/9f2c1b... -H "X-API-Key: ..."
# -> {"status": "running"}  ...then the full result once done

Webhook payload (only sent when something is wrong — flow-failed or visual-change):

{
  "event": "flow-failed",
  "flow": "booking-journey", "url": "https://your-site.com/en/ski-rental",
  "run": "9f2c1b...", "ok": false, "changed": 0,
  "failures": [{"device": "iphone-14",
                "step": {"i": 3, "verb": "waitFor", "error": "Timeout 10000ms exceeded..."},
                "failScreenshot": "https://grid.jipidy.com/shots/.../iphone-14--FAILED.png"}]
}

Scheduled runs count against your monthly quota like any other run; when quota is exhausted they pause until the next month. Stored auth is encrypted at rest and only decrypted at run time — it is never returned by any endpoint.

Baselines

The first run of a URL (per device / per checkpoint label) creates the baseline automatically. Promote a later run to be the new baseline:

curl -X POST https://grid.jipidy.com/api/baseline \
  -H "X-API-Key: $JIPIDY_KEY" -H "Content-Type: application/json" \
  -d '{"run": "9f2c1b..."}'

Other endpoints

GET /api/usagecurrent month usage vs quota
GET /api/devicesdevice list + defaults
GET /api/flow/verbsflow verbs + limits
GET /healthservice health

Status codes

200run complete (shots: even if some devices failed — check results[].ok)
422flow: at least one device failed a step
401bad API key
402monthly quota exceeded
429more than 2 concurrent runs, or rate-limited
400invalid input (bad URL, bad steps, SSRF-blocked target)

CI example (GitLab)

visual-check:
  stage: test
  image: curlimages/curl
  script:
    - |
      curl -f -s -X POST https://grid.jipidy.com/api/flow \
        -H "X-API-Key: $JIPIDY_KEY" -H "Content-Type: application/json" \
        -d "{\"url\": \"$REVIEW_APP_URL\", \"video\": true, \"steps\": [
              {\"waitFor\": {\"selector\": \"#app\"}},
              {\"screenshot\": \"home\"}
            ]}" | tee grid-result.json
  artifacts:
    paths: [grid-result.json]
    when: always

The -f makes curl exit non-zero on HTTP 422 ⇒ the job fails when a journey breaks on any device.