> For the complete documentation index, see [llms.txt](https://synap.ac/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://synap.ac/docs/api/reference/preflight/complete-a-networkcheck.md).

# Complete a NetworkCheck

Reports what the browser measured. Responds with how the connection looks to the candidate. The detail, including results the candidate is not shown, is kept for reviewers. A check can be completed once.

```json
{"openapi":"3.0.1","info":{"title":"Synap API","version":"3.0.0"},"tags":[{"name":"Preflight","description":"Endpoints related to the checks a candidate runs before an exam."}],"servers":[{"url":"https://api.synap.ac/v3","description":"Production"},{"url":"https://api-stage.synap.ac/v3","description":"Staging"}],"security":[{"SessionAuth":[]},{"PATAuth":[]},{"AutomationAuth":[]},{"LegacySessionAuth":[]}],"components":{"securitySchemes":{"SessionAuth":{"type":"http","scheme":"bearer","description":"Authorize the request using a Session Token.","bearerFormat":"r:<token>"},"PATAuth":{"type":"http","scheme":"bearer","description":"Authorise the request using a personal access token.","bearerFormat":"p:"},"AutomationAuth":{"type":"http","scheme":"bearer","description":"Authorise the request with a short-lived token signed by the automations engine on behalf of a workflow owner.","bearerFormat":"a:<token>"},"LegacySessionAuth":{"type":"apiKey","description":"[Legacy] Authorize the request using a Session Token.","in":"header","name":"X-Syn-Session-Token"}},"schemas":{"ObjectId":{"type":"string","description":"The primary key for each resource."},"NetworkCheck":{"type":"object","required":["id","type"],"properties":{"id":{"$ref":"#/components/schemas/ObjectId"},"type":{"type":"string","description":"Identifies the Resource.","enum":["NetworkCheck"]},"attributes":{"type":"object","properties":{"key":{"type":"string","minLength":16,"maxLength":128,"writeOnly":true,"description":"The key held by the browser or desktop app reporting this run. Required for runs issued with a key."},"writerGeneration":{"type":"integer","minimum":1,"writeOnly":true,"description":"The reporting generation issued when the run was created or resumed. Send the same generation when starting and completing a check."},"downloadUrl":{"type":"string","readOnly":true,"description":"The file to download. Only on the response that starts a check; add a query string that changes each time so nothing is served from the browser’s cache."},"downloadBytes":{"type":"integer","minimum":1,"readOnly":true,"description":"How many bytes the download file holds."},"expiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"When the upload addresses stop working. Only on the response that starts a check."},"uploads":{"type":"array","readOnly":true,"description":"Where to upload to, with a PUT of exactly sizeBytes of data and the stated content type. The same address may be used repeatedly until it expires. Only on the response that starts a check.","items":{"type":"object","required":["name","url","sizeBytes","contentType"],"properties":{"name":{"type":"string"},"url":{"type":"string"},"sizeBytes":{"type":"integer","minimum":1},"contentType":{"type":"string"}}}},"probes":{"type":"array","readOnly":true,"description":"Addresses of the exam’s own hosts. Request each with a plain no-cors GET: any answer at all, even an error page, means the host can be reached. Only on the response that starts a check.","items":{"type":"object","required":["name","url"],"properties":{"name":{"type":"string","enum":["files","storage"]},"url":{"type":"string"}}}},"services":{"type":"array","readOnly":true,"description":"The proctoring connections a proctored exam depends on, each to be tried the way the exam uses it: a WebSocket is opened and must answer, and the video relay must hand out a relay candidate to a peer connection that only accepts relayed ones. Left out for an exam that is not proctored. Only on the response that starts a check.","items":{"type":"object","required":["name","kind"],"properties":{"name":{"type":"string","enum":["synoptic","turn"]},"kind":{"type":"string","enum":["websocket","turn"]},"url":{"type":"string","description":"The WebSocket address, for a websocket service."},"urls":{"type":"array","items":{"type":"string"},"description":"The ICE server addresses, for a turn service."},"username":{"type":"string"},"credential":{"type":"string"}}}},"metrics":{"type":"object","additionalProperties":false,"required":["durationMs"],"description":"What the candidate’s browser measured. Every part is optional except how long the check took, and a part the browser could not measure is left out.","properties":{"durationMs":{"type":"number","minimum":0,"maximum":600000},"reachability":{"type":"object","additionalProperties":false,"description":"Whether the browser got any answer at all from the exam’s own hosts, which the probes it was handed point at. A part the browser could not test is left out.","properties":{"files":{"type":"boolean","description":"The host exam media is served from."},"storage":{"type":"boolean","description":"The accelerated storage endpoint answers are uploaded to."},"synoptic":{"type":"boolean","description":"The proctoring server answered over a WebSocket. Only for a proctored attempt."},"turn":{"type":"boolean","description":"The video relay handed out a relay candidate. Only for a proctored attempt."}}},"synopticSocket":{"type":"object","additionalProperties":false,"required":["heldMs","closedEarly"],"description":"How the proctoring socket fared once it had answered: the browser holds it open for the rest of the check, so a network that lets a WebSocket open and then cuts it off shows up here. Left out when the socket never answered.","properties":{"heldMs":{"type":"number","minimum":0,"maximum":600000,"description":"How long the socket stayed open before the browser let it go, or before the network closed it."},"closedEarly":{"type":"boolean","description":"The network closed the socket before the browser let it go."},"closeCode":{"type":"integer","minimum":0,"maximum":65535,"description":"The WebSocket close code, when the network closed it."}}},"probes":{"type":"object","additionalProperties":false,"required":["attempts","failures"],"description":"Every small request made during the check: reachability probes, API pings and the latency requests.","properties":{"attempts":{"type":"integer","minimum":0,"maximum":10000},"failures":{"type":"integer","minimum":0,"maximum":10000}}},"api":{"type":"object","additionalProperties":false,"required":["count","failures"],"properties":{"count":{"type":"integer","minimum":0,"maximum":10000},"failures":{"type":"integer","minimum":0,"maximum":10000},"medianMs":{"type":"number","minimum":0,"maximum":600000},"p95Ms":{"type":"number","minimum":0,"maximum":600000}},"description":"Authenticated pings of the API."},"latency":{"type":"object","additionalProperties":false,"description":"Small requests to the download host, while nothing else was moving and while a transfer was.","properties":{"idle":{"type":"object","additionalProperties":false,"required":["count","failures"],"properties":{"count":{"type":"integer","minimum":0,"maximum":10000},"failures":{"type":"integer","minimum":0,"maximum":10000},"medianMs":{"type":"number","minimum":0,"maximum":600000},"p95Ms":{"type":"number","minimum":0,"maximum":600000}}},"loaded":{"type":"object","additionalProperties":false,"required":["count","failures"],"properties":{"count":{"type":"integer","minimum":0,"maximum":10000},"failures":{"type":"integer","minimum":0,"maximum":10000},"medianMs":{"type":"number","minimum":0,"maximum":600000},"p95Ms":{"type":"number","minimum":0,"maximum":600000}}}}},"download":{"type":"object","additionalProperties":false,"required":["bytes","durationMs","failed","aborted"],"properties":{"bytes":{"type":"number","minimum":0,"maximum":1000000000},"durationMs":{"type":"number","minimum":0,"maximum":600000},"throughputMbps":{"type":"number","minimum":0,"maximum":100000},"longestStallMs":{"type":"number","minimum":0,"maximum":600000,"description":"The longest stretch in which no data moved while the transfer was under way."},"failed":{"type":"boolean","description":"The request errored."},"aborted":{"type":"boolean","description":"The client gave up because no data moved for several seconds. A transfer that was only cut off by the time allowed, while still moving, is neither failed nor aborted."}}},"upload":{"type":"object","additionalProperties":false,"required":["bytes","durationMs","failed","aborted"],"properties":{"bytes":{"type":"number","minimum":0,"maximum":1000000000},"durationMs":{"type":"number","minimum":0,"maximum":600000},"throughputMbps":{"type":"number","minimum":0,"maximum":100000},"longestStallMs":{"type":"number","minimum":0,"maximum":600000,"description":"The longest stretch in which no data moved while the transfer was under way."},"failed":{"type":"boolean","description":"The request errored."},"aborted":{"type":"boolean","description":"The client gave up because no data moved for several seconds. A transfer that was only cut off by the time allowed, while still moving, is neither failed nor aborted."}}},"connection":{"type":"object","additionalProperties":false,"description":"What the browser says about the connection, kept as context only.","properties":{"effectiveType":{"type":"string","maxLength":16},"downlinkMbps":{"type":"number","minimum":0,"maximum":100000},"rttMs":{"type":"number","minimum":0,"maximum":600000},"saveData":{"type":"boolean"}}}},"writeOnly":true},"overall":{"type":"string","enum":["ok","warn","error"],"readOnly":true,"description":"How the candidate’s connection looks, from the results that clearly mean trouble. Only on the response that completes a check."}}},"relationships":{"type":"object","properties":{"preflightRun":{"type":"object","description":"This is a resource linkage for a to-one relationship. It is like a Parse Pointer.","readOnly":false,"properties":{"data":{"type":"object","required":["id","type"],"nullable":true,"properties":{"id":{"$ref":"#/components/schemas/ObjectId"},"type":{"type":"string","description":"Identifies the Resource.","enum":["PreflightRun"]}}}}}}}}},"BadRequestApiError":{"type":"object","description":"The request was invalid.","properties":{"id":{"type":"string","description":"Unique ID of this error occurrence."},"status":{"type":"string","description":"HTTP status code."},"code":{"type":"string","description":"Synap internal error code."},"title":{"type":"string"},"detail":{"type":"string"},"source":{"type":"object","properties":{"pointer":{"type":"string"},"parameter":{"type":"string"}}}}},"UnauthorizedApiError":{"type":"object","description":"Unauthorized request.","properties":{"id":{"type":"string","description":"Unique ID of this error occurrence."},"status":{"type":"string","description":"HTTP status code."},"code":{"type":"string","description":"Synap internal error code."},"title":{"type":"string"},"detail":{"type":"string"},"source":{"type":"object","properties":{"pointer":{"type":"string"},"parameter":{"type":"string"}}}}},"ForbiddenApiError":{"type":"object","description":"Forbidden request.","properties":{"id":{"type":"string","description":"Unique ID of this error occurrence."},"status":{"type":"string","description":"HTTP status code."},"code":{"type":"string","description":"Synap internal error code."},"title":{"type":"string"},"detail":{"type":"string"},"source":{"type":"object","properties":{"pointer":{"type":"string"},"parameter":{"type":"string"}}}}},"NotFoundApiError":{"type":"object","description":"The request resource could not be found.","properties":{"id":{"type":"string","description":"Unique ID of this error occurrence."},"status":{"type":"string","description":"HTTP status code."},"code":{"type":"string","description":"Synap internal error code."},"title":{"type":"string"},"detail":{"type":"string"},"source":{"type":"object","properties":{"pointer":{"type":"string"},"parameter":{"type":"string"}}}}},"ApiError":{"type":"object","description":"This is an error response structure. The id, status, code, title and detail will vary based on the error situation.","properties":{"id":{"type":"string","description":"Unique ID of this error occurrence."},"status":{"type":"string","description":"HTTP status code."},"code":{"type":"string","description":"Synap internal error code."},"title":{"type":"string"},"detail":{"type":"string"},"source":{"type":"object","properties":{"pointer":{"type":"string"},"parameter":{"type":"string"}}}}}}},"paths":{"/network-checks/{object_id}":{"patch":{"summary":"Complete a NetworkCheck","description":"Reports what the browser measured. Responds with how the connection looks to the candidate. The detail, including results the candidate is not shown, is kept for reviewers. A check can be completed once.","tags":["Preflight"],"parameters":[{"name":"object_id","in":"path","required":true,"schema":{"$ref":"#/components/schemas/ObjectId"}}],"requestBody":{"required":true,"content":{"application/vnd.api+json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/NetworkCheck"}}}}}},"responses":{"200":{"description":"Success","content":{"application/vnd.api+json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/NetworkCheck"}}}}}},"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/vnd.api+json":{"schema":{"type":"object","properties":{"errors":{"type":"array","items":{"$ref":"#/components/schemas/BadRequestApiError"}}}}}}},"401":{"description":"Unauthorized","content":{"application/vnd.api+json":{"schema":{"type":"object","properties":{"errors":{"type":"array","items":{"$ref":"#/components/schemas/UnauthorizedApiError"}}}}}}},"403":{"description":"Forbidden","content":{"application/vnd.api+json":{"schema":{"type":"object","properties":{"errors":{"type":"array","items":{"$ref":"#/components/schemas/ForbiddenApiError"}}}}}}},"404":{"description":"Not Found","content":{"application/vnd.api+json":{"schema":{"type":"object","properties":{"errors":{"type":"array","items":{"$ref":"#/components/schemas/NotFoundApiError"}}}}}}},"409":{"description":"The reporting session has been replaced.","content":{"application/vnd.api+json":{"schema":{"type":"object","properties":{"errors":{"type":"array","items":{"$ref":"#/components/schemas/ApiError"}}}}}}}},"operationId":"networkChecks.completeNetworkCheck"}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://synap.ac/docs/api/reference/preflight/complete-a-networkcheck.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
