> ## Documentation Index
> Fetch the complete documentation index at: https://nova.dweet.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Changelog

> Latest updates and improvements to the Nova Embed API

<Update label="June 2026" tags={["Scoring", "Errors"]}>
  ### Malformed PDFs with escaped line endings fail before queueing

  PDF resumes whose structural line endings are escaped can now fail during scoring intake with `RESUME_CORRUPTED`. Nova doesn't create scoring jobs for these requests, so single-score submissions return HTTP 422 and batch submissions return the affected applications in `rejectedApplications`.

  These pre-queue rejections do not emit `score.failed` webhooks. For batch submissions, `rejectedApplications[].error.reason` may include `escaped_pdf_line_endings`.

  [Learn more about supported resume formats](/embed-api/guides/supported-formats)
</Update>

<Update label="May 2026" tags={["Scoring", "Errors"]}>
  ### Batch scoring now returns per-application intake rejections

  Batch submissions can now accept valid applications while returning invalid resume inputs in `rejectedApplications`. These pre-queue rejections do not create scoring jobs and do not emit `score.failed` webhooks. Batch status responses include the same `rejectedApplications` list, and all-invalid batches return `422 VALIDATION_ERROR` with per-application details.

  [Learn more about batch scoring](/embed-api/endpoints/score-batch)
</Update>

<Update label="May 2026" tags={["Scoring", "Errors"]}>
  ### Scoring intake now catches corrupted PDF resumes

  Scoring requests with truncated or malformed PDF resumes now fail during intake with `RESUME_CORRUPTED` and HTTP 422. Nova doesn't create a scoring job for these requests, so you get a concrete error while the submission is still actionable.

  Source download problems still return `RESUME_FETCH_FAILED`. That keeps corrupted file bytes separate from temporary URL, network, or storage issues.

  [Learn more about supported resume formats](/embed-api/guides/supported-formats)
</Update>

<Update label="May 2026" tags={["Data Retention", "Deletion"]}>
  ### Application and tenant deletion requests

  You can now request application-level or tenant-level deletion through the Embed API. Deletion runs asynchronously, returns a deletion request ID, and exposes polling for completion.

  **New endpoints:**

  * `DELETE /v1/jobs/{jobId}/applications/{applicationId}`
  * `DELETE /v1/tenants/{tenantExternalId}`
  * `GET /v1/deletion-requests/{deletionRequestId}`

  [Read the deletion request guide](/embed-api/endpoints/deletion/overview)
</Update>

<Update label="April 2026" tags={["Rate Limits"]}>
  ### Dedicated bucket for current criteria reads

  `GET /v1/jobs/{jobId}/criteria/versions/current` now uses its own bucket, `criteria_current_reads`, with a limit of `60 req/s`.

  This route was a high-volume first-party read path. Splitting it out keeps it from competing with other `read_and_ops` traffic and makes rate-limit debugging easier.

  **What changed:**

  * `criteria_current_reads` is now a separate bucket in rate-limit headers and `GET /v1/rate-limit-status`
  * `read_and_ops` still covers other read/write endpoints, but no longer includes the current criteria version route

  [Learn more about rate limits](/embed-api/concepts/rate-limits)
</Update>

<Update label="February 2026" tags={["Scoring", "Webhooks"]}>
  ### Scoring responses and webhooks now include `criteriaVersionId`

  Scoring job HTTP responses and `score.completed` / `score.failed` webhook payloads now include `criteriaVersionId`. Use this field to identify which criteria snapshot was used for scoring, and fetch it via `GET /v1/jobs/{jobId}/criteria/versions/{criteriaVersionId}`.

  This is an additive change. No existing fields were removed or renamed.
</Update>

<Update label="February 2026" tags={["Criteria"]}>
  ### Criteria version endpoints moved under `/criteria/versions`

  Criteria version operations now use a nested URL structure:

  * `GET /v1/jobs/{jobId}/criteria/versions/current`
  * `GET /v1/jobs/{jobId}/criteria/versions`
  * `GET /v1/jobs/{jobId}/criteria/versions/{criteriaVersionId}`

  The version snapshot and current-version endpoints now return a consistent envelope shape:

  ```json theme={null}
  {
    "version": {
      "id": "cmlz26ck2000awp61q9qcjcne",
      "version": 3,
      "status": "ACTIVE",
      "createdAt": "2026-02-17T12:00:00.000Z",
      "archivedAt": null
    },
    "criteria": [
      {
        "id": "crit_...",
        "text": "...",
        "importance": "MUST_HAVE",
        "order": 0
      }
    ]
  }
  ```

  <Warning>
    Breaking change: legacy endpoints under `/v1/jobs/{jobId}/criteria-versions*` were removed.
  </Warning>
</Update>

<Update label="February 2026" tags={["Rate Limits", "Scoring"]}>
  ### Bucket-based rate limiting

  Rate limiting now uses a **per-bucket, per-second** model scoped by partner and environment. Every authenticated `/v1/*` request is classified into 1 of 5 buckets, each with its own limit:

  | Bucket                  | Limit                  | Endpoints                           |
  | ----------------------- | ---------------------- | ----------------------------------- |
  | `criteria_ai`           | 2 req/s + 4 concurrent | Question sets, criteria generations |
  | `scoring_intake_batch`  | 1 req/s                | Scoring batches                     |
  | `scoring_intake_single` | 10 req/s               | Single scoring jobs                 |
  | `read_and_ops`          | 20 req/s               | All other reads and operations      |
  | `rate_limit_status`     | 2 req/s                | Rate limit status endpoint          |

  **Key changes:**

  * **All endpoints are now rate-limited**, not just scoring endpoints
  * **New headers**: `X-RateLimit-Bucket` identifies which bucket a request was classified into, `X-RateLimit-Degraded` signals when rate limiting is operating in degraded mode
  * **`GET /v1/rate-limit-status`** now returns per-bucket breakdown with in-flight concurrency status. No longer requires `X-Tenant-Id`
  * **Scoring batch size** reduced from 100 to 25 applications per request
  * **Fail-open posture**: if the rate limiting backend is temporarily unavailable, requests pass through instead of being blocked

  [Learn more about rate limits](/embed-api/concepts/rate-limits)

  ### Get Score by Application: look up scores without a scoring job ID

  New endpoint `GET /v1/jobs/{jobId}/applications/{applicationId}/score` retrieves the latest scoring result using just the job ID and application ID. No need to persist Nova's `scoringJobId`.

  Use it when your integration doesn't store scoring job IDs, after a rescore to get the latest result, or to build dashboards that show scores by application.

  [Learn more](/embed-api/endpoints/score-by-application)
</Update>

<Update label="February 2026" tags={["Scoring", "Webhooks"]}>
  ### Simplified scoring status values

  Scoring job and batch `status` values are now simplified to a 3-state model:

  * `pending`: Not finished yet
  * `completed`: Finished successfully
  * `failed`: Finished with an error. For batches, this includes partial failures

  **Key changes:**

  * Scoring job `status` no longer returns `PROCESSING`
  * Batch `status` no longer returns `IN_PROGRESS` or `PARTIAL_FAILURE`
  * `batch.completed` webhook payload `status` now uses `completed` or `failed`

  <Warning>
    Breaking change: if your integration previously handled status values like `PROCESSING`, `IN_PROGRESS`, or `PARTIAL_FAILURE`, update your logic to use `pending|completed|failed`.
  </Warning>
</Update>

<Update label="December 2025" tags={["Criteria"]}>
  ### Criteria Library: store and reuse criteria across jobs

  Build a library of reusable screening criteria at the tenant level. Save commonly-used criteria once, then add them to any job with a single API call.

  **New endpoints:**

  * `GET /v1/criteria-library` - List library criteria
  * `GET /v1/criteria-library/{criterionId}` - Get a library criterion
  * `POST /v1/criteria-library` - Add a criterion to the library
  * `PATCH /v1/criteria-library/{criterionId}` - Update a library criterion
  * `DELETE /v1/criteria-library/{criterionId}` - Remove from library

  **Key features:**

  * **Tenant-scoped**: Each of your customers has their own isolated library
  * **Reusable**: Use library criteria as templates when building job-scoped criteria

  [Learn more](/embed-api/concepts/criteria-library)
</Update>
