---
title: "Read-only activity submission reconciliation"
method: POST
path: "/api/activities/submissions/lookup"
tags: ["Activities"]
---

# Read-only activity submission reconciliation

`POST /api/activities/submissions/lookup`

## Request

- Base URL: `https://courseprofiler.com`
- URL: `https://courseprofiler.com/api/activities/submissions/lookup`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer
  - none

Read-only POST: credentials are in the body, not a URL. Reads the same caller/key reservation/outcome; never fetches source data, writes, renews ownership or recomputes analysis. Missing reservation is not proof an unkeyed job is absent.

## Request body

- ActivityLookupRequest
  - `idempotency` ActivityIdempotency, required: Optional caller-scoped idempotency. Requires the server flag enabled. API keys are optional: anonymous callers must supply a stable private caller_token; API-key callers must omit it.
    - `key` string, required: Stable random per-submission key. Never reuse an expired key.
    - `caller_token` string: Anonymous callers only: 32 cryptographic random bytes encoded as canonical unpadded base64url. Keep private and persist before submission. Never put in URLs, logs or request IDs.

## Response `200`

Read report; inspect submission.state and error, not just HTTP 200

- ActivityResponse
  - `request_id` string
  - `job` ActivityJob, required: Existing PublicApiJob serialization. Empty result_artifacts, warnings, errors and progress may be omitted by NON_EMPTY; no change to legacy job serialization.
    - `request_id` RequestId (unresolved $ref)
    - `job_persistence` JobPersistence (unresolved $ref)
    - `submission_request_id` SubmissionRequestId (unresolved $ref)
    - `job_id` JobId, required (unresolved $ref)
    - `status` Status, required (unresolved $ref)
    - `status_url` StatusUrl, required (unresolved $ref)
    - `created_at` CreatedAt, required (unresolved $ref)
    - `started_at` StartedAt (unresolved $ref)
    - `completed_at` CompletedAt (unresolved $ref)
    - `expires_at` ExpiresAt, required (unresolved $ref)
    - `result_artifacts` ResultArtifacts (unresolved $ref)
    - `warnings` Warnings (unresolved $ref)
    - `errors` Errors (unresolved $ref)
    - `progress` Progress (unresolved $ref)
  - `summary` object, nullable, required
  - `submission` ActivitySubmission
    - `state` 'completed' | 'failed' | 'outcome_unknown', required: outcome_unknown can mean still running or interrupted. Never triggers automatic re-execution.
    - `replayed` boolean, required
    - `job_id` string, required
    - `submission_request_id` string, required
    - `job_persistence` JobPersistence, required (unresolved $ref)
    - `expires_at` string, date-time, required: Replay window: at most 30 days, capped by configured job retention. Reservation markers remain after expiry; expired keys are rejected.
  - `error` ApiProblem
    - `code` string, required
    - `message` string, required
    - `severity` 'info' | 'warning' | 'error', required
    - `field` string
    - `details` object

## Other responses

- `400`: Invalid input before reservation; not replay-recorded.
- `404`: submission_not_found; not absence of an unkeyed job.
- `410`: submission_expired; expired key is blocked, not reused.
- `500`: Invalid stored metadata or recorded terminal failure.
- `503`: idempotency_disabled, submission_outcome_unknown, storage failure or recorded terminal storage failure. Keep the same caller/key; never blindly start a new submission.

---

[API](https://skmtc.dev/courseprofiler/apis/courseprofiler-public-api.md) · [All operations](https://skmtc.dev/courseprofiler/apis/courseprofiler-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/courseprofiler/apis/courseprofiler-public-api/revisions/e07403d7dba9?raw)
