Read analysis as results arrive
Retrieve stored findings, activity and evidence, including partial results. Poll safely without starting scans.
Read existing stored results. These GET requests do not start scans, generate AI analysis, reserve scan allowance or change reports. Report creation and profile imports remain the ways to admit new work.
1. Find usable results without waiting for everyone
curl "https://app.linkwiz.ai/api/v1/reports/REPORT_ID/analysis" \
-H "Authorization: Bearer YOUR_API_KEY"Use a report ID from GET /reports. One finalized person with an answered check can make a ten-person report useful. has_usable_results answers whether anything is usable; availability is none, partial or available. Verified empty activity is also a usable observation. Company identity alone is not.
Read work.state separately: not_requested, queued, processing, completed, completed_with_issues, failed or unknown. Processing includes collection and analysis; there is no separate measured AI stage or ETA. all_requested_work_terminal can be true even with failures. all_requested_work_succeeded is true only when requested work succeeded. Neither predicts future scheduled work.
No results yet returns HTTP 200 with honest empty values. A failed scan is a state in a successful read, not an HTTP 500. A report can have available but stale results while a refresh waits in the queue.
Fictional example: one analyzed person out of ten
{
"data": {
"report": {
"id": "11111111-1111-4111-8111-111111111111",
"name": "Northstar Example report",
"archived": false,
"company": {
"name": "Northstar Example",
"domain": "northstar.example",
"linkedin_url": "https://www.linkedin.com/company/northstar-example/",
"observed_context": null
}
},
"links": {
"workspace_url": "https://app.linkwiz.ai/w/example/reports/northstar-example",
"public_url": null
},
"availability": "partial",
"has_usable_results": true,
"coverage": {
"person_profiles": 10,
"optimization": {
"analyzed_profiles": 1,
"answered_checks": 1,
"unknown_checks": 0,
"profiles_without_usable_analysis": 9
},
"activity": {
"observed_person_profiles": 0,
"company_page_observed": false,
"incomplete_person_profiles": 10
}
},
"work": {
"state": "queued",
"all_requested_work_terminal": false,
"all_requested_work_succeeded": false,
"counts": {
"requested": 21,
"queued": 20,
"processing": 0,
"succeeded": 1,
"failed": 0,
"inaccessible": 0,
"cancelled": 0,
"warnings": 0
},
"scan_run_ids": [
"33333333-3333-4333-8333-333333333333",
"77777777-7777-4777-8777-777777777777"
]
},
"freshness": {
"state": "unknown",
"reasons": [
"incomplete_profile_coverage",
"incomplete_activity_coverage"
],
"oldest_captured_at": "2026-09-18T09:00:00Z",
"newest_captured_at": "2026-09-18T09:00:00Z"
},
"evaluated_at": "2026-09-18T09:03:00Z",
"results_revision": "836259acab0682bf902a23c71940f0888f4fdd281e2632d40d2a5fb37ac0d3ff",
"work_revision": "bedf9683b14f51bcefd08e052d2027d910954168b111af970290d3d4661900a8",
"collections": {
"profiles_revision": "34609394fab12344e99ceacc02fffe2f546d8ed5abdfc489408ac2056953d4f6",
"activity_revision": "5948aee2c1c852712c4c25c7cbcdbe28a18a703808b28343d5f38e98afbf6403"
},
"optimization_summary": {
"method": "existing_profile_check_aggregation",
"cohort_profile_count": 1,
"counts": {
"good": 0,
"optimize": 1,
"answered": 1,
"unknown": 0,
"score_pct": 0
},
"categories": [
{
"id": "aggregate_example_category",
"key": "Profile",
"good": 0,
"optimize": 1,
"answered": 1,
"score_pct": 0,
"revision": "03e8f0be7fc01d2ef470937ae1ed915a3305e49c8fab01e8d28b250beb2837e7"
}
],
"checks": [
{
"id": "aggregate_example_headline",
"key": "profile.headline_company",
"good": 0,
"optimize": 1,
"answered": 1,
"score_pct": 0,
"revision": "03e8f0be7fc01d2ef470937ae1ed915a3305e49c8fab01e8d28b250beb2837e7"
}
]
},
"limitations": [
{
"code": "incomplete_profile_coverage",
"message": "One of ten people has usable profile analysis."
}
]
},
"request_id": "99999999-9999-4999-8999-999999999999"
}2. Retrieve findings and supporting evidence
curl "https://app.linkwiz.ai/api/v1/reports/REPORT_ID/analysis/profiles?limit=10" \
-H "Authorization: Bearer YOUR_API_KEY"Each ID identifies a person attached to this report. Use profile_id to select one attachment. Unanalyzed people remain present with analysis: null and a reason. Stored checks include an outcome, recommendation when available, observed value, source link and eligible screenshot references. Unknown is not a failed check. Internal prompts, credentials and worker payloads are excluded.
recommendation is stored, generic guidance, not a personalized finding. It may be present even when outcome is good and may contain [company name] or {company}. Use improvement advice only for optimize checks supported by non-conflicting evidence. Render company placeholders from the summary’s report.company.name after validating that context; if it is unavailable, use neutral wording such as “the company”. Never treat a non-null recommendation as proof that a profile failed a check. Keep quoted evidence unchanged.
Report totals aggregate existing non-null checks only: answered = good + optimize, score = good / answered × 100. With no answered checks, the score is null. Unknown checks and unanalyzed profiles are reported separately. Category/check totals are not invented company insights; use the profile findings to identify their supporting observations. No charts, exports or generated narratives are added.
3. Read activity and company context
curl "https://app.linkwiz.ai/api/v1/reports/REPORT_ID/analysis/activity?event_type=post&limit=25" \
-H "Authorization: Bearer YOUR_API_KEY"Posts, reposts, comments and reactions identify their actor and source. Company-page actors are separate from people and never increase the analyzed-person count. The summary exposes existing company tagline and industry when eligible; it does not invent a company analysis.
Optional filters: profile_id, event_type, occurred_from and occurred_to. Dates accept RFC 3339 with an offset, start inclusive and end exclusive. Unknown dates are excluded only when a date filter is used. Ordering is stable ID order, not newest-first. An empty page alone does not prove no activity exists: inspect coverage and limitations to distinguish a verified empty scan from inaccessible or unfinished collection.
Activity and engagement are observations, not a complete LinkedIn history. Null counts mean unknown. Ambiguous retained data can be withheld after an unfinished refresh; this is not evidence that the original LinkedIn post was deleted.
4. Understand age and limitations
captured_at records the source observation, available_at its verified finalization, and updated_at a trustworthy visible-change time where known. Unknown timestamps remain null. evaluated_at is the read time, not a fresh scan. Provenance distinguishes scanner, legacy and unknown sources.
freshness.state is current, stale or unknown. Current means current stored observation relative to known work, not proof that LinkedIn is unchanged. Newer requested work or a failed refresh can leave older usable results marked stale. Use capture dates for your own age threshold; no automatic expiry is introduced. Report oldest/newest capture dates and component coverage expose mixed ages.
Fictional example: usable older findings after a failed refresh
{
"data": {
"report": {
"id": "11111111-1111-4111-8111-111111111111",
"name": "Northstar Example report",
"archived": false,
"company": {
"name": "Northstar Example",
"domain": "northstar.example",
"linkedin_url": "https://www.linkedin.com/company/northstar-example/",
"observed_context": null
}
},
"links": {
"workspace_url": "https://app.linkwiz.ai/w/example/reports/northstar-example",
"public_url": null
},
"availability": "partial",
"has_usable_results": true,
"coverage": {
"person_profiles": 10,
"optimization": {
"analyzed_profiles": 1,
"answered_checks": 1,
"unknown_checks": 0,
"profiles_without_usable_analysis": 9
},
"activity": {
"observed_person_profiles": 0,
"company_page_observed": false,
"incomplete_person_profiles": 10
}
},
"work": {
"state": "queued",
"all_requested_work_terminal": false,
"all_requested_work_succeeded": false,
"counts": {
"requested": 21,
"queued": 20,
"processing": 0,
"succeeded": 0,
"failed": 1,
"inaccessible": 0,
"cancelled": 0,
"warnings": 0
},
"scan_run_ids": [
"33333333-3333-4333-8333-333333333333",
"77777777-7777-4777-8777-777777777777"
]
},
"freshness": {
"state": "stale",
"reasons": [
"latest_attempt_failed",
"incomplete_profile_coverage",
"incomplete_activity_coverage"
],
"oldest_captured_at": "2026-09-18T09:00:00Z",
"newest_captured_at": "2026-09-18T09:00:00Z"
},
"evaluated_at": "2026-09-18T10:00:00Z",
"results_revision": "e2ff9fba7f23350025019be57cd20ef3d4deb422f99b3b876146a18b4b78e3f2",
"work_revision": "2391b31b1a0740f1a545df2461ace3b8492279ca4a4b404d4926252e52e390ad",
"collections": {
"profiles_revision": "0adecb44bf3a86d2c7baf1b25987c1f9b8bee1211603c07f34a40ee6f74ab85d",
"activity_revision": "5948aee2c1c852712c4c25c7cbcdbe28a18a703808b28343d5f38e98afbf6403"
},
"optimization_summary": {
"method": "existing_profile_check_aggregation",
"cohort_profile_count": 1,
"counts": {
"good": 0,
"optimize": 1,
"answered": 1,
"unknown": 0,
"score_pct": 0
},
"categories": [
{
"id": "aggregate_example_category",
"key": "Profile",
"good": 0,
"optimize": 1,
"answered": 1,
"score_pct": 0,
"revision": "03e8f0be7fc01d2ef470937ae1ed915a3305e49c8fab01e8d28b250beb2837e7"
}
],
"checks": [
{
"id": "aggregate_example_headline",
"key": "profile.headline_company",
"good": 0,
"optimize": 1,
"answered": 1,
"score_pct": 0,
"revision": "03e8f0be7fc01d2ef470937ae1ed915a3305e49c8fab01e8d28b250beb2837e7"
}
]
},
"limitations": [
{
"code": "incomplete_profile_coverage",
"message": "One of ten people has usable profile analysis."
}
]
},
"request_id": "99999999-9999-4999-8999-999999999999"
}5. Poll and reconcile safely
Start around 30 seconds with jitter while work is outstanding, then slow to 1–5 minutes or stop when your integration has what it needs. Coordinate all reports against the shared limits returned by /context. These are suggested intervals, not permission to exceed rate limits.
- Read summary and compare each collection revision with the last fully saved revision.
- For a changed collection, request the first page with
expected_revisionfrom the summary. Stage every page with unchanged filters, limit and cursor. - Stop only when the top-level
next_cursoris null. Analysis pages use top-levelrevisionandnext_cursor, unlike the existing roster endpoint. - After a complete traversal, atomically save the new collection and enqueue downstream changes. Upsert by ID and revision; reconcile absent records only within that completed collection/filter.
- On 409
results_changed, discard staged pages and restart with bounded backoff. On any incomplete traversal, keep the previous saved state and infer no deletions.
results_revision tracks visible report results; work_revision tracks work. Collection and individual revisions support deduplication. They are opaque hashes, not chronological counters or an event log. Polling can miss intermediate states and does not promise exactly-once delivery. Profiles and activity are separate consistent traversals; there is no cross-collection snapshot transaction, delta feed, webhook or ETag/304 support.
Download the tested JavaScript polling example. Run it on a server or trusted automation host, never in browser code with a secret. It stages an unfiltered collection, retries revision conflicts up to three attempts and returns changed/removed records only after success. Persist state plus downstream work atomically; use report, collection, ID and revision as your downstream idempotency identity.
import { readAnalysisCollection } from "./analysis-polling.mjs";
const result = await readAnalysisCollection({
key: process.env.LINKWIZ_API_KEY,
reportId: "REPORT_ID", kind: "profiles",
previous: savedState // null on the first run
});
// In one database transaction: save result.state and enqueue
// result.changed / result.removed. On error, retain savedState.
// Schedule the next poll with jitter and account-wide pacing.6. Download screenshots with authorization
Use the returned evidence.images[].url with the bearer header on a trusted server. Do not put the secret in a URL or make an unauthenticated browser image tag. References identify the current eligible screenshot; downloads recheck report access and key status. JPEG, PNG and WebP up to 10 MiB are supported. Original and preview variants may be available. No raw Storage paths or signed credentials are exposed.
Missing or changed media returns 404 evidence_unavailable; a foreign, removed or obsolete reference returns 404 not_found. Use text/source evidence or the report link as a fallback. Re-fetch current references when appropriate. Revocation denies new requests; a previously authorized download may finish, and downloaded copies cannot be recalled.
Access, limits and recovery
The summary requires reports:read and analysis:read. Profiles, activity and evidence also require profiles:read. All permissions includes these scopes; explicit restricted keys may need updating. Existing workspace, issuer, subscription/API access and history rules still apply. Public report visibility does not grant access to underlying API fields. Workspace links need normal access; public links appear only when sharing is enabled.
Profiles default to 10 per page, maximum 25; activity defaults to 25, maximum 100. Limits are upper bounds: pages can contain fewer complete records under the 2 MiB response budget. No text is silently shortened. Cursors expire after 15 minutes and are bound to report, workspace, route, filters, limit and revision. Restart expired traversal from the beginning. No multi-report or multi-ID batch is available.
422 result_too_large means one stored record exceeds the bound; reducing the page limit cannot fix it. Contact support with the request ID. For 401/403 or disabled access, correct access/configuration before retrying. On 429 respect Retry-After; on unexpected 500 use bounded backoff. Read error.retryable and next_action, retaining request_id. Never treat a scan failure as an instruction to create more paid work.
Data and evidence responses are private, no-store and noindex. Keep credentials and downloaded evidence protected. See the complete schemas and shared error contract.