agmission/Development/server/docs/Data_Export_API.postman_collection.json

383 lines
16 KiB
JSON

{
"info": {
"name": "AgMission — Data Export API",
"description": "End-to-end testing collection for the Data Export API.\n\n## Setup\n1. Set the `baseUrl` variable to your server (e.g. `https://localhost:4100`).\n2. Log in via **[Auth] Login** — the `jwt` variable is captured automatically.\n3. Use **[Keys] Create API Key** — the `apiKey` variable is captured automatically.\n4. Set `jobId` and `fileId` to real IDs from your database.\n\n## Folders\n- **[Auth]** — Get a JWT for key-management endpoints\n- **[Keys]** — Manage API keys (`/api/keys`, JWT-protected)\n- **[Public API]** — Data export endpoints (`/api/v1/`, X-API-Key protected)\n- **[Export Workflow]** — Full async export flow (trigger → poll → download)",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"variable": [
{ "key": "baseUrl", "value": "https://localhost:4100", "type": "string" },
{ "key": "jwt", "value": "", "type": "string", "description": "Captured automatically by the Login request" },
{ "key": "apiKey", "value": "", "type": "string", "description": "Captured automatically by Create API Key" },
{ "key": "keyId", "value": "", "type": "string", "description": "Captured automatically by Create API Key" },
{ "key": "jobId", "value": "12345", "type": "string", "description": "AgMission job ID (integer)" },
{ "key": "fileId", "value": "", "type": "string", "description": "AppFile _id — captured from Get Sessions response" },
{ "key": "exportId", "value": "", "type": "string", "description": "Captured automatically by Trigger Export" }
],
"item": [
{
"name": "[Auth]",
"item": [
{
"name": "Login (get JWT)",
"event": [
{
"listen": "test",
"script": {
"exec": [
"const r = pm.response.json();",
"if (r && r.token) {",
" pm.collectionVariables.set('jwt', r.token);",
" console.log('JWT captured');",
"}"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [{ "key": "Content-Type", "value": "application/json" }],
"body": {
"mode": "raw",
"raw": "{\n \"username\": \"your@email.com\",\n \"password\": \"yourpassword\"\n}"
},
"url": {
"raw": "{{baseUrl}}/api/users/login",
"host": ["{{baseUrl}}"],
"path": ["api", "users", "login"]
},
"description": "Standard AgMission login. Stores the returned JWT in the `jwt` collection variable for subsequent key-management requests."
}
}
]
},
{
"name": "[Keys] API Key Management",
"description": "JWT-protected endpoints for managing API keys. Pass the JWT from the Login request in the Authorization header.",
"item": [
{
"name": "Create API Key",
"event": [
{
"listen": "test",
"script": {
"exec": [
"const r = pm.response.json();",
"if (r && r.key) {",
" pm.collectionVariables.set('apiKey', r.key);",
" pm.collectionVariables.set('keyId', r._id);",
" console.log('API Key captured — save it now, it will not be shown again:', r.key);",
"}"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [
{ "key": "Content-Type", "value": "application/json" },
{ "key": "Authorization", "value": "Bearer {{jwt}}" }
],
"body": {
"mode": "raw",
"raw": "{\n \"label\": \"Postman Test Key\",\n \"service\": \"data_export\"\n}",
"options": { "raw": { "language": "json" } }
},
"url": {
"raw": "{{baseUrl}}/api/keys",
"host": ["{{baseUrl}}"],
"path": ["api", "keys"]
},
"description": "Creates a new API key. The plain `key` field is returned **once** — the test script captures it to `apiKey`. `service` can be `data_export` (default) or `partner_api`."
}
},
{
"name": "List API Keys",
"request": {
"method": "GET",
"header": [
{ "key": "Authorization", "value": "Bearer {{jwt}}" }
],
"url": {
"raw": "{{baseUrl}}/api/keys",
"host": ["{{baseUrl}}"],
"path": ["api", "keys"]
},
"description": "Returns all keys (active and revoked) for the authenticated applicator. Admins can append `?ownerId=<ObjectId>` to list another account's keys."
}
},
{
"name": "Revoke API Key",
"request": {
"method": "DELETE",
"header": [
{ "key": "Authorization", "value": "Bearer {{jwt}}" }
],
"url": {
"raw": "{{baseUrl}}/api/keys/{{keyId}}",
"host": ["{{baseUrl}}"],
"path": ["api", "keys", "{{keyId}}"]
},
"description": "Soft-deletes the key (sets `active: false`). Uses the `keyId` variable captured by Create API Key."
}
},
{
"name": "Create API Key (Admin — on behalf of owner)",
"request": {
"method": "POST",
"header": [
{ "key": "Content-Type", "value": "application/json" },
{ "key": "Authorization", "value": "Bearer {{jwt}}" }
],
"body": {
"mode": "raw",
"raw": "{\n \"label\": \"Partner Integration Key\",\n \"service\": \"partner_api\",\n \"ownerId\": \"<applicator_user_id>\"\n}",
"options": { "raw": { "language": "json" } }
},
"url": {
"raw": "{{baseUrl}}/api/keys",
"host": ["{{baseUrl}}"],
"path": ["api", "keys"]
},
"description": "Admin-only. Creates a key for a different account by supplying `ownerId`. Key will have `managedBy: 'admin'`."
}
}
]
},
{
"name": "[Public API] /api/v1",
"description": "External data-export endpoints. All require the `X-API-Key` header with the full 64-char hex key captured by Create API Key.",
"item": [
{
"name": "Get Sessions (job summary)",
"event": [
{
"listen": "test",
"script": {
"exec": [
"const r = pm.response.json();",
"// Capture first fileId for the records endpoint",
"if (r && r.sessions && r.sessions.length > 0) {",
" pm.collectionVariables.set('fileId', r.sessions[0].fileId);",
" console.log('fileId captured:', r.sessions[0].fileId);",
"}"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "GET",
"header": [
{ "key": "X-API-Key", "value": "{{apiKey}}" }
],
"url": {
"raw": "{{baseUrl}}/api/v1/jobs/{{jobId}}/sessions",
"host": ["{{baseUrl}}"],
"path": ["api", "v1", "jobs", "{{jobId}}", "sessions"]
},
"description": "Returns one session summary per uploaded application file for the job.\n\n- `reportConfirmed: false` means the applicator has not yet confirmed values in Report Settings — re-fetch when this flips.\n- `avgSpraySpeed` is in m/s (metric) or mph (US — not applicable to this endpoint, metric only).\n- Captures the first `fileId` for use in the records endpoint."
}
},
{
"name": "Get Session Records (raw GPS trace)",
"request": {
"method": "GET",
"header": [
{ "key": "X-API-Key", "value": "{{apiKey}}" }
],
"url": {
"raw": "{{baseUrl}}/api/v1/jobs/{{jobId}}/sessions/{{fileId}}/records?limit=100&interval=1",
"host": ["{{baseUrl}}"],
"path": ["api", "v1", "jobs", "{{jobId}}", "sessions", "{{fileId}}", "records"],
"query": [
{ "key": "limit", "value": "100", "description": "Max records per page (default 500, max 2000)" },
{ "key": "interval", "value": "1", "description": "Return one record per N seconds of GPS time (thinning). Remove for all points." },
{ "key": "startingAfter", "value": "", "description": "Cursor for next page — use _id from last record of previous page", "disabled": true }
]
},
"description": "Paginated raw GPS trace for one session file. Cursor-based pagination using `startingAfter=<record._id>`.\n\n`sprayStat` values:\n- `0` = spray off\n- `1` / `2` = spray on (application data)\n- `3` = segment START marker (filtered out automatically)"
}
},
{
"name": "Get Spray Areas (GeoJSON)",
"request": {
"method": "GET",
"header": [
{ "key": "X-API-Key", "value": "{{apiKey}}" }
],
"url": {
"raw": "{{baseUrl}}/api/v1/jobs/{{jobId}}/areas",
"host": ["{{baseUrl}}"],
"path": ["api", "v1", "jobs", "{{jobId}}", "areas"]
},
"description": "Returns a GeoJSON FeatureCollection of planned spray-area polygons for the job. Suitable for ArcGIS / QGIS import."
}
}
]
},
{
"name": "[Export Workflow] Async Bulk Export",
"description": "Full async export flow: POST trigger → GET poll until ready → GET download.\n\nRun in order:\n1. Trigger Export\n2. Poll Export Status (repeat until `status` = `ready`)\n3. Download Export File",
"item": [
{
"name": "1 — Trigger Export (CSV, metric)",
"event": [
{
"listen": "test",
"script": {
"exec": [
"const r = pm.response.json();",
"if (r && r.exportId) {",
" pm.collectionVariables.set('exportId', r.exportId);",
" console.log('exportId captured:', r.exportId);",
"}"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [
{ "key": "Content-Type", "value": "application/json" },
{ "key": "X-API-Key", "value": "{{apiKey}}" }
],
"body": {
"mode": "raw",
"raw": "{\n \"format\": \"csv\",\n \"interval\": 1,\n \"units\": \"metric\"\n}",
"options": { "raw": { "language": "json" } }
},
"url": {
"raw": "{{baseUrl}}/api/v1/jobs/{{jobId}}/export",
"host": ["{{baseUrl}}"],
"path": ["api", "v1", "jobs", "{{jobId}}", "export"]
},
"description": "Triggers async export generation. Returns `exportId` immediately (status = `pending`).\n\nBody fields:\n- `format`: `csv` | `geojson`\n- `interval`: GPS thinning in seconds (omit for all points)\n- `units`: `metric` (default) | `us`"
}
},
{
"name": "1 — Trigger Export (CSV, US units)",
"event": [
{
"listen": "test",
"script": {
"exec": [
"const r = pm.response.json();",
"if (r && r.exportId) {",
" pm.collectionVariables.set('exportId', r.exportId);",
" console.log('exportId captured (US units):', r.exportId);",
"}"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [
{ "key": "Content-Type", "value": "application/json" },
{ "key": "X-API-Key", "value": "{{apiKey}}" }
],
"body": {
"mode": "raw",
"raw": "{\n \"format\": \"csv\",\n \"interval\": 1,\n \"units\": \"us\"\n}",
"options": { "raw": { "language": "json" } }
},
"url": {
"raw": "{{baseUrl}}/api/v1/jobs/{{jobId}}/export",
"host": ["{{baseUrl}}"],
"path": ["api", "v1", "jobs", "{{jobId}}", "export"]
},
"description": "Same as CSV metric but with `units: 'us'`. Column headers will use US unit suffixes (e.g. `groundSpeed_mph`, `alt_ft`, `temp_f`, `appRateApplied_galAc`)."
}
},
{
"name": "1 — Trigger Export (GeoJSON)",
"event": [
{
"listen": "test",
"script": {
"exec": [
"const r = pm.response.json();",
"if (r && r.exportId) {",
" pm.collectionVariables.set('exportId', r.exportId);",
" console.log('exportId captured (GeoJSON):', r.exportId);",
"}"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [
{ "key": "Content-Type", "value": "application/json" },
{ "key": "X-API-Key", "value": "{{apiKey}}" }
],
"body": {
"mode": "raw",
"raw": "{\n \"format\": \"geojson\"\n}",
"options": { "raw": { "language": "json" } }
},
"url": {
"raw": "{{baseUrl}}/api/v1/jobs/{{jobId}}/export",
"host": ["{{baseUrl}}"],
"path": ["api", "v1", "jobs", "{{jobId}}", "export"]
},
"description": "Triggers a GeoJSON FeatureCollection export with all GPS points (no thinning)."
}
},
{
"name": "2 — Poll Export Status",
"event": [
{
"listen": "test",
"script": {
"exec": [
"const r = pm.response.json();",
"console.log('Export status:', r.status, '| units:', r.units, '| format:', r.format);",
"if (r.status === 'ready') {",
" console.log('Ready to download:', r.downloadUrl);",
"} else if (r.status === 'error') {",
" console.error('Export failed:', r.error);",
"}"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "GET",
"header": [
{ "key": "X-API-Key", "value": "{{apiKey}}" }
],
"url": {
"raw": "{{baseUrl}}/api/v1/exports/{{exportId}}",
"host": ["{{baseUrl}}"],
"path": ["api", "v1", "exports", "{{exportId}}"]
},
"description": "Poll until `status` = `ready`. When ready, the response includes `downloadUrl`. Possible statuses: `pending` | `processing` | `ready` | `error`."
}
},
{
"name": "3 — Download Export File",
"request": {
"method": "GET",
"header": [
{ "key": "X-API-Key", "value": "{{apiKey}}" }
],
"url": {
"raw": "{{baseUrl}}/api/v1/exports/{{exportId}}/download",
"host": ["{{baseUrl}}"],
"path": ["api", "v1", "exports", "{{exportId}}", "download"]
},
"description": "Streams the generated file with `Content-Disposition: attachment`. The file is deleted from disk after streaming (TTL = 24 hours). Only works when status = `ready`.\n\nIn Postman, use **Save Response → Save to a file** to download."
}
}
]
}
]
}