Organizer-owned catalog, statements, attachments and submission receipts.
Tokens bind one contest and one team. Never put a token in a URL.
Full protocol notes (Markdown source)
# API contracts and the Quera integration boundary
Version 1 is an **organizer-owned protocol**, not an assertion about Quera's undocumented internal API. Its public staging base URL is `https://api.pardisboard.ir`; documentation is at `/docs/`. Requests use `Authorization: Bearer <run-token>` over HTTPS; loopback HTTP is allowed only for development or an SSH tunnel. Each token binds one contest and one team. No account selector or upstream URL is accepted from the agent.
| Route | Meaning |
|---|---|
| `GET /healthz` | Public, minimal liveness response; no deployment or secret data |
| `GET /openapi.json` | Public API schema only; no contest data or credentials |
| `GET /v1/contest` | Bound contest ID and capabilities; no other-contest enumeration |
| `GET /v1/problems` | Complete author-supplied catalog for the bound contest |
| `GET /v1/problems/{id}` | One problem including exact submission format metadata |
| `GET /v1/attachments/{problem-id}--{index}` | Attachment JSON with base64 bytes, size and SHA-256 |
| `POST /v1/submissions` | Opt-in forwarding of a file to Quera; disabled in staging |
| `GET /v1/submissions/{id}` | Own receipt/uncertain state; actual verdict adapter still required |
The fixture service implements pending/final verdicts for contract tests. The catalog service truthfully returns `capabilities.verdicts=false`; it does not synthesize judge results. It returns `submissions=false` until live forwarding is enabled. Add a verified verdict adapter before official contest use.
## Problem descriptor
See `examples/catalog.json`. Required fields: `id`, `title`, `question_type`, `statement_markdown`, `file_types`, and `grading.automatic=true`. `samples`, `attachments` and `api_metadata` preserve optional details. The type string is extensible; do not hard-code a fixed exhaustive set. Every allowed file type has its numeric Quera ID and exact formatting instructions. Include language version, archive layout, selected-option encoding, text encoding, file size/extension restrictions and partial-score semantics in the descriptor where relevant.
Catalog v1 has a proposed 16 MB encoded catalog cap and 10 MiB per inline attachment. Larger datasets must be moved to a separately authenticated, contest-scoped attachment store with streamed downloads and hashes before using those problems. Do not truncate silently or serve arbitrary remote URLs; that can introduce SSRF and leak the unseen final. These limits may need expansion once actual question assets are known.
## Submission envelope
```json
{
"problem_id": "309026",
"request_id": "unique-id-for-this-attempt",
"answer": {
"file_type": 58,
"filename": "result.zip",
"content_base64": "<base64 of the exact bytes>"
}
}
```
File bytes may contain code, plain text, JSON, selected options, a ZIP or any other format supported by that particular Quera question. The transport does not decide the answer format. Fixture IDs 1/2/3/4/6/91 are synthetic; `58` is the supplied example's file type, not verified universal ZIP metadata. Names must be plain ASCII basenames, never paths. Current file cap is 10 MiB.
`request_id` is stable across transport retries of the same answer, and different for intentionally new attempts. Same ID with different content returns conflict. Bridge persistence prevents forwarding the same request twice, even after restart. Because the upstream Quera example has no idempotency key, a crash between upstream acceptance and bridge acknowledgement leaves an uncertain record. Exactly-once judge acceptance cannot be promised; reconciliation is necessary.
Read API responses: 401 wrong/expired token; 403 disabled submissions; 404 missing/unreleased resource; 409 idempotency conflict; 429 submission limits; 201 upstream receipt confirmed; 202 upstream receipt uncertain. A final verdict, when implemented, must distinguish pending from final and preserve score and official timestamps. HTTP status alone never proves correctness.
## Confirmed Quera contract
User-supplied working example, forwarded 2026-08-20:
- `POST https://quera.org/judge_api/apikey-judge/`
- Header `Judge-APIKey`; multipart fields `problem_id`, `file_type`, `file`.
- Expected successful receipt: HTTP 201.
- Key acquisition page: `https://quera.org/judge_api/my-apikey/`.
- Example problem: `https://quera.org/course/assignments/91102/problems/309026`, `file_type=58`.
`organizer/quera.py` implements that request with redirects disabled, a per-run problem/file-type allowlist, bounded payloads, sanitized errors and no automatic POST retries. It does not claim a submission ID or verdict schema that was not provided. The raw API key stays in the trusted bridge, never a participant image.
## Research outcome and remaining requirements
Unauthenticated GET of the supplied problem and key page redirects to Quera login; GET of the submission route returns 405. Public pages show contest/problem structure but do not document a complete authenticated read/result/scoreboard API. The research did not establish those contracts. This is not proof that no internal API exists. It is a reason to use our own catalog and obtain the judge-result/scoreboard contract from Quera's platform team.
Question listing, reading and attachments are implemented by our own API from author source files; no public API is required for those reads. Quera verdict retrieval and official scoreboard export remain necessary. A documented, administrator-provided export can feed the merger without a scoreboard API. Do not reverse-engineer authenticated actions or treat another product named Quera/QuEra as this platform's API.
## Live conformance matrix
For **each actual API-supported question type**, add a test case with real problem ID and allowed file types; correct answer file; incorrect answer file; malformed answer; all attachments and expected hashes; pending-to-final result; score/subtask interpretation; rejudge result; deadline behavior; and proof the score appears on the correct team's scoreboard. Recheck zip/binary transport byte-for-byte. Keep account credentials and private expected answers outside the participant ZIP and public repositories.
Use `tools.live_submit` only with a dedicated authorized test problem. The kit does not contain a live key and has made no authenticated Quera submissions. The seven-format fixture matrix proves protocol handling, not compatibility with all real Quera types.