Common Patterns
Bulk-fetch verified Claims, request and track reproductions, handle 429 backoff, index arXiv papers, and embed badges in your README.
Bulk-fetch verified Claims
List public repositories first (sorted by updatedAt descending, up to 50 entries; each entry includes claimCount, verifiedClaimCount, and runCount summaries for rough filtering), then fetch each snapshot and filter verified Claims with jq:
# List owner/slug of public repositories
curl https://citeark.com/api/repositories \
| jq -r '.repositories[] | "\(.owner)/\(.slug)"'
# Fetch one repository snapshot and filter verified claims
curl "https://citeark.com/api/repositories?owner=<owner>&slug=<slug>" \
| jq '.repository.claims[] | select(.verification == "verified")'Request a reproduction
Submit a run request with the repository.id from the snapshot and the claim.id you want verified. A 202 response means the run is queued; afterwards, re-fetch the snapshot to track state changes in runs (full flow below):
curl -X POST https://citeark.com/api/runs \
-H "x-api-key: $CITEARK_API_KEY" \
-H "content-type: application/json" \
-d '{"repositoryId": "…", "claimId": "CLM-001"}'This is currently a controlled private beta: only experiments using the platform-controlled executor (builtin) are accepted. License metadata controls source redistribution, not isolated execution. At most 10 submissions per hour. General-purpose Agent reproduction of arbitrary third-party code is not open yet.
Embed a badge in your README
Badges are issued live by the platform from the repository's current data (SVG, cached for 5 minutes). Link the badge back to the repository page so readers can drill into Claims, run records, and evidence:
[](https://citeark.com/r/<owner>/<slug>)See Badges & Embedding for how levels are determined.
Request and track a full reproduction
Chain the earlier steps into a complete flow: read snapshot → submit run → poll status → verify signature.
GET /api/repositories?owner&slugto read the snapshot; noterepository.idand the targetclaim.id;POST /api/runsto submit the run; takerun.idfrom the 202 response —stateisqueuedat this point;- Poll the same snapshot endpoint and watch that run's
stateinruns[](poll no faster than every 10 seconds); - Once
statereaches a terminalverified/failed, readrun.attestation; if you need independent signature verification, callGET /api/attestations/{digest}by digest.
OWNER="…" # repository owner
SLUG="…" # repository slug
# 1) Read the snapshot; note repository.id and the target claim.id
SNAPSHOT=$(curl -s "https://citeark.com/api/repositories?owner=$OWNER&slug=$SLUG")
REPO_ID=$(echo "$SNAPSHOT" | jq -r '.repository.id')
CLAIM_ID=$(echo "$SNAPSHOT" | jq -r '.repository.claims[0].id')
# 2) Submit the run; take run.id from the 202 response (state=queued)
RUN_ID=$(curl -s -X POST https://citeark.com/api/runs \
-H "x-api-key: $CITEARK_API_KEY" \
-H "content-type: application/json" \
-d "{\"repositoryId\": \"$REPO_ID\", \"claimId\": \"$CLAIM_ID\"}" \
| jq -r '.run.id')
# 3) Poll the same snapshot endpoint; extract this run's state with jq
while true; do
STATE=$(curl -s "https://citeark.com/api/repositories?owner=$OWNER&slug=$SLUG" \
| jq -r --arg id "$RUN_ID" '.repository.runs[] | select(.id == $id) | .state')
echo "run $RUN_ID state: $STATE"
case "$STATE" in verified|failed) break ;; esac
sleep 10
done
# 4) After a terminal state, verify the signature by digest (the attestations path parameter drops the sha256: prefix)
DIGEST=$(curl -s "https://citeark.com/api/repositories?owner=$OWNER&slug=$SLUG" \
| jq -r --arg id "$RUN_ID" '.repository.runs[] | select(.id == $id) | .attestation.statementDigest' \
| sed 's/^sha256://')
curl -s "https://citeark.com/api/attestations/$DIGEST" | jq '.verified'Handle 429s and back off
When limits are exceeded, endpoints return 429 with two kinds of headers that call for different backoff strategies (see Rate Limits & Quotas for details):
| Type | Response headers | How to handle |
|---|---|---|
| Rate limit | Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining | Recovers automatically after the window; wait Retry-After seconds and retry |
| Monthly quota | Retry-After, X-Quota-Limit, X-Quota-Used, X-Quota-Reset | Resets only next month (Retry-After points at the UTC reset time in X-Quota-Reset); stop retrying and surface the error |
HEADERS=$(mktemp)
while true; do
STATUS=$(curl -s -D "$HEADERS" -o /tmp/citeark-body.json -w '%{http_code}' \
https://citeark.com/api/repositories)
[ "$STATUS" != "429" ] && break
if grep -qi '^X-Quota-Limit:' "$HEADERS"; then
# Monthly quota exhausted: retrying is pointless; wait for the next-month reset indicated by X-Quota-Reset
echo "Monthly quota exhausted; resets at:" \
"$(grep -i '^X-Quota-Reset:' "$HEADERS" | tr -d '\r' | awk '{print $2}')" >&2
exit 1
fi
# Rate limit: back off per Retry-After (seconds), then retry
RETRY_AFTER=$(grep -i '^Retry-After:' "$HEADERS" | tr -d '\r' | awk '{print $2}')
sleep "${RETRY_AFTER:-60}"
done
cat /tmp/citeark-body.jsonIndex an arXiv paper
arXiv papers need no file upload — indexing takes three steps:
GET /api/arxiv?input=2401.12345to fetch metadata and thesuggestedSlug(requiresreadscope, so an API Key is required);POST /api/repositorieswith{"input": "2401.12345"}— title, abstract, license, and PDF are all extracted server-side;GET /api/processing?repositoryId=…to poll processing status untiljob.statebecomescompleted.
# 1) Query arXiv metadata and suggestedSlug (requires read scope)
curl "https://citeark.com/api/arxiv?input=2401.12345" \
-H "x-api-key: $CITEARK_API_KEY" | jq '.metadata.suggestedSlug'
# 2) Submit for indexing; returns 201 with repository.id
curl -X POST https://citeark.com/api/repositories \
-H "x-api-key: $CITEARK_API_KEY" \
-H "content-type: application/json" \
-d '{"input": "2401.12345"}'
# 3) Poll processing status until completed
curl "https://citeark.com/api/processing?repositoryId=<repository-id>" \
-H "x-api-key: $CITEARK_API_KEY" | jq '.job.state'Track a private or organization repository
Pass visibility=private or owner=<org-slug> to POST /api/repositories to create the repository in your private space or under an organization. Reading private repositories requires the corresponding permission; unauthorized public queries only see the projected information (see the public projection section in Core Concepts).