The TypeScript and Python SDKs are generated from the review API's OpenAPI document, version 1.0.0. Each operation in the API reference that returns JSON is a typed method, and both SDKs add pagination, waiting for a review, retries and typed errors.
Install#
The TypeScript package is @proofline/sdk and needs Node 22 or newer. The Python package needs Python 3.11 or newer. Neither package is on npm or PyPI yet; ask us for a build while they are not.
Both clients take a token explicitly or read PROOFLINE_TOKEN from the environment. They keep the token in memory, never write it to disk, and redact it from their diagnostic output.
Create a client#
import { ProoflineClient } from "@proofline/sdk";
const client = new ProoflineClient({
baseUrl: "https://proofline.sh",
token: process.env.PROOFLINE_TOKEN!,
});import os
from proofline import ProoflineClient
client = ProoflineClient(os.environ["PROOFLINE_TOKEN"])# curl has no client to create: every request carries the token itself.
curl -sS "https://proofline.sh/api/v1/organizations/$PROOFLINE_ORGANIZATION_ID/reviews?limit=1" \
-H "Authorization: Bearer $PROOFLINE_TOKEN"The Python client holds HTTP connections, so use it as a context manager or call close(). AsyncProoflineClient has the same methods as coroutines. The TypeScript client uses the platform's fetch and has nothing to close.
Page through reviews#
iterReviews and iter_reviews follow the cursor from page to page with the same filters. They stop after 100 pages or 10,000 reviews unless you set other limits, and they refuse a cursor that repeats.
import { ProoflineClient } from "@proofline/sdk";
const client = new ProoflineClient({
baseUrl: "https://proofline.sh",
token: process.env.PROOFLINE_TOKEN!,
});
const reviews = client.iterReviews(
{ path: { org_id: process.env.PROOFLINE_ORGANIZATION_ID! } },
{ maxItems: 50 },
);
for await (const review of reviews) {
console.log(review.id, review.kind, review.status);
}import os
from uuid import UUID
from proofline import ProoflineClient
with ProoflineClient(os.environ["PROOFLINE_TOKEN"]) as client:
organization_id = UUID(os.environ["PROOFLINE_ORGANIZATION_ID"])
for review in client.iter_reviews(organization_id, max_items=50):
print(review.id, review.kind, review.status)# The SDKs follow the cursor for you. Over HTTP, this reads the first page.
# While a page's "truncated" is true, request the next one with the same
# filters and that page's "next_cursor" as "cursor".
curl -sS "https://proofline.sh/api/v1/organizations/$PROOFLINE_ORGANIZATION_ID/reviews?limit=50" \
-H "Authorization: Bearer $PROOFLINE_TOKEN"Wait for a review#
waitForReview and wait_for_review poll a review until it finishes or the deadline passes. They wait 5 seconds first, then double the wait up to 60 seconds. The result has a status, the review's console address and what each assessment could not establish.
| Status | Meaning |
|---|---|
COMPLETED | Every assessment finished and recorded its checks. |
INCOMPLETE | The review finished, but an assessment has an unknown state, an unresolved check or an evidence gap. |
FAILED | The review failed. |
STOPPED | The review stopped before it finished. |
TIMED_OUT | The deadline passed first. The result keeps the latest review it read. |
A completed review tells you the review ran. Read its findings and evidence before you decide to deploy.
import { ProoflineClient, ProoflineError } from "@proofline/sdk";
const client = new ProoflineClient({
baseUrl: "https://proofline.sh",
token: process.env.PROOFLINE_TOKEN!,
});
const orgId = process.env.PROOFLINE_ORGANIZATION_ID!;
try {
const page = await client.listReviews({ path: { org_id: orgId }, query: { limit: 1 } });
const latest = page.items[0];
if (latest !== undefined) {
const result = await client.waitForReview(orgId, latest.id, { timeoutMs: 20 * 60_000 });
console.log(result.status, result.reviewUrl);
for (const gap of result.gaps) {
console.log(gap.assessmentId, gap.reasonCodes);
}
}
} catch (error) {
if (error instanceof ProoflineError) console.error(error.status, error.type);
else throw error;
}import os
from uuid import UUID
from proofline import ProoflineClient, ProoflineError
try:
with ProoflineClient(os.environ["PROOFLINE_TOKEN"]) as client:
organization_id = UUID(os.environ["PROOFLINE_ORGANIZATION_ID"])
page = client.list_reviews(organization_id, limit=1)
for review in page.items:
result = client.wait_for_review(organization_id, review.id, timeout=20 * 60)
print(result.status, result.review_url)
for gap in result.gaps:
print(gap.assessment_id, gap.reason_codes)
except ProoflineError as error:
print(error.status, error.type)# The SDKs poll for you and derive the statuses above from the review's
# assessments. Over HTTP, read the review again until its status is no longer
# PENDING or RUNNING, then read each assessment's gaps yourself.
curl -sS "https://proofline.sh/api/v1/organizations/$PROOFLINE_ORGANIZATION_ID/reviews/$REVIEW_ID" \
-H "Authorization: Bearer $PROOFLINE_TOKEN"Errors and retries#
A refused request raises ProoflineError with the problem's status, type and detail. An invalid response or a network failure raises it with a fixed SDK problem type.
The clients retry a GET that returns 429 or 503 up to 3 times. They wait for Retry-After up to 60 seconds and refuse a longer one. A review request or rerun is sent once, because repeating a pull request review request or a rerun can start another review. Requests time out after 30 seconds, and a response body is limited to 8 MiB.