# Getting started Four steps: get an agent running on a device, approve the device from the pulsar webapp, send a fetch request, poll for the result. ## Prerequisites - An SGApps account. - One of three agent carriers available on the device: - **AB Desktop** with a Pulsar preset attached (recommended for fleet operators). - **AB Desktop homepage** set to `/pulsar/agent/ui` (zero preset config). - **A standalone browser** on the operator's PC (Chrome, Chromium, Firefox) launched with CORS/mixed-content flags. - The device can reach `https:///pulsar/agent/ui`. The pulsar webapp **Install** tab generates the exact launcher command for each of the three modes, per OS, with a Copy button. ## 1. Register the agent The agent URL is a constant: `https:///pulsar/agent/ui`. No query string, no token. On first open, the agent sends `/pulsar/agent/api/session` with its `bid` (buildIdentifier for AB, `browser-` for browsers). The server either: - **Approves** the request (BID already in `pulsarApprovedDevices` for some owner) → session opens, agent starts polling. - **Returns `403 device-pending`** (BID unknown) → inserts a row in `pulsarPendingDevices`, waits for an owner to approve from the pulsar webapp **Devices** tab. ## 2. Approve the device Open the pulsar webapp (`/online/webapp/pulsar`) → **Devices** tab → **Pending** section. Click **Approve** on the row matching the agent's BID (the agent-ui shows its own BID in the Device identity panel — Copy from there if needed). Approval: - inserts `pulsarApprovedDevices` with `{ownerUserId: , bid, approvedByUserId, approvedAt, label?}`, - deletes the pending row. The agent retries session automatically on next tick. ## 3. Send a fetch request ```bash curl -X POST https:///pulsar/api/fetch \ -H "Cookie: " \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/data.json", "method": "GET", "headers": {"User-Agent": "my-tool/1.0"}, "timeoutMs": 10000, "maxResponseBytes": 2097152 }' ``` Response (fast path — if a device is ready and the fetch finishes before you poll): ```json { "status": "ok", "data": { "jobId": "6531a0f1d84a2e5c82b17ad0", "state": "pending", "retryAfterMs": 500 } } ``` ## 4. Poll for the result ```bash curl https:///pulsar/api/job/6531a0f1d84a2e5c82b17ad0 \ -H "Cookie: " ``` The response is one of: ```json {"status":"ok","data":{"state":"pending","retryAfterMs":500}} {"status":"ok","data":{"state":"dispatched","retryAfterMs":1500}} {"status":"ok","data":{"state":"done","result":{ "status": 200, "statusText": "OK", "headers": {"content-type": "application/json"}, "body": "{\"ok\":true}", "bodyBase64": false, "cropped": false, "cropOriginalSize": null, "elapsedMs": 182, "bytesWritten": 12 }}} {"status":"ok","data":{"state":"failed","error":{"code":"timeout","message":"request timed out"}}} {"status":"ok","data":{"state":"expired"}} ``` Poll with the server-provided `retryAfterMs` as a lower bound. Don't poll faster — you'll just add noise. ## Full round-trip, one shell session ```bash # 1. submit JOB=$(curl -s -X POST https:///pulsar/api/fetch \ -H "Cookie: " -H "Content-Type: application/json" \ -d '{"url":"https://httpbin.org/ip","method":"GET"}' | jq -r .data.jobId) # 2. poll until settled while :; do R=$(curl -s https:///pulsar/api/job/$JOB -H "Cookie: ") STATE=$(echo "$R" | jq -r .data.state) case "$STATE" in done|failed|expired) echo "$R" | jq .; break ;; *) sleep $(echo "$R" | jq -r '.data.retryAfterMs/1000') ;; esac done ``` ## Advanced: range requests ```json { "url": "https://example.com/large.pdf", "method": "GET", "rangeRequest": {"start": 0, "end": 65535} } ``` The agent will add `Range: bytes=0-65535` to the outbound request. ## Advanced: HTTPS cert override for testing ```json { "url": "https://self-signed.local/api", "method": "GET", "allowInsecureTLS": true } ``` The job is only dispatched to agents whose `insecureTLS` capability is set to `accept`. If no such agent is online for your account, the request fails with `503 no-active-agents` (even if other agents are online, they refuse by policy). ## Advanced: private-IP override ```json { "url": "http://192.168.1.42/local-api", "method": "GET", "allowPrivateIP": true } ``` Same gating as `allowInsecureTLS` — only agents with `privateIP: accept` capability see the job.