> ## 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.

# Score Batch

> Submit multiple applications for scoring in a single request

Submit multiple applications for scoring in a single request. Results are delivered individually via webhook.

If some resume inputs are invalid, Nova accepts the valid applications and returns the invalid ones in `rejectedApplications`. Rejected applications are pre-queue intake rejections: no scoring job is created and no `score.failed` webhook is emitted for them.

## Request

<CodeGroup>
  ```typescript TypeScript SDK theme={null}
  import { Nova } from '@nova-sdk/api';

  const nova = new Nova({
    apiKey: process.env.NOVA_API_KEY!,
    tenantId: 'acme-corp',
  });

  const { batch, scoringJobIds, acceptedApplications, rejectedApplications } =
    await nova.jobs.scoringBatches.submit({
    jobId: 'job-123',
    body: {
      jobDescription: 'We are looking for a Senior Backend Engineer with 5+ years of experience in Node.js and TypeScript...',
      roleKnowledge: "Team values applicants who've built systems from scratch. Strong preference for distributed systems experience over frontend-heavy backgrounds.",
      applications: [
        {
          applicationId: 'app-001',
          resume: { type: 'url', url: 'https://storage.example.com/resumes/001.pdf' },
        },
        {
          applicationId: 'app-002',
          resume: { type: 'text', content: '# Jane Smith\n\nSenior Backend Engineer with 7 years of experience...' },
          applicationData: {
            applicationAnswers: [
              { question: 'Are you eligible to work in the UK?', answer: 'Yes' },
            ],
            context: 'Internal recruiter note: Strong referral from engineering lead. Applicant expressed interest in platform team specifically.',
          },
        },
      ],
    },
  });

  console.log(acceptedApplications);
  console.log(rejectedApplications);
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://embed.nova.dweet.com/v1/jobs/job-123/scoring-batches' \
    -H 'Authorization: Bearer sk_live_your_key' \
    -H 'X-Tenant-Id: acme-corp' \
    -H 'Content-Type: application/json' \
    -d '{
      "jobDescription": "We are looking for a Senior Backend Engineer with 5+ years of experience in Node.js and TypeScript...",
      "roleKnowledge": "Team values applicants who'\''ve built systems from scratch.",
      "applications": [
        {
          "applicationId": "app-001",
          "resume": { "type": "url", "url": "https://storage.example.com/resumes/001.pdf" }
        },
        {
          "applicationId": "app-002",
          "resume": { "type": "text", "content": "# Jane Smith\n\nSenior Backend Engineer with 7 years of experience..." },
          "applicationData": {
            "applicationAnswers": [
              { "question": "Are you eligible to work in the UK?", "answer": "Yes" }
            ],
            "context": "Internal recruiter note: Strong referral from engineering lead."
          }
        }
      ]
    }'
  ```
</CodeGroup>

<Note>
  Include `jobDescription` at the batch level. It applies to all applications in the batch. See [Data Retention](/embed-api/concepts/data-retention) for storage details.
</Note>

## Idempotency

Re-submitting the same `jobId` and set of `applicationId` values returns the existing batch.

<Note>
  This endpoint uses built-in batch scoring idempotency. `Idempotency-Key` is ignored here. To recover from a timeout or network uncertainty, re-submit the same batch for the same `jobId`. To create fresh scoring work for an application, use the single scoring endpoint with `rescore`.
</Note>

If a previous submission rejected an application and you later fix that resume, re-submitting the exact same batch shape returns the original rejection. Submit the corrected application with a distinct batch shape or use the single scoring endpoint.

The HTTP replay header `Idempotent-Replayed: true` never appears on this endpoint because batch scoring stays outside the generic `Idempotency-Key` middleware.

See [Idempotency](/embed-api/concepts/idempotency) for the full retry model.

## Limits

* 1 to 25 applications per request

## Response

The API returns `202 Accepted`.

```json theme={null}
{
  "batch": {
    "id": "cmlz26em4002cwp61t7ukh3lb",
    "jobId": "job-123",
    "status": "pending",
    "totalJobs": 2,
    "completedJobs": 0,
    "failedJobs": 0,
    "createdAt": "2025-12-14T10:30:45Z",
    "completedAt": null
  },
  "scoringJobIds": ["cmlz26dl3001bwp61r8sjf2ka", "cmlz26dl3001bwp61r8sjf2kb"],
  "acceptedApplications": [
    {
      "applicationId": "app-001",
      "scoringJobId": "cmlz26dl3001bwp61r8sjf2ka"
    },
    {
      "applicationId": "app-002",
      "scoringJobId": "cmlz26dl3001bwp61r8sjf2kb"
    }
  ],
  "rejectedApplications": []
}
```

`totalJobs`, `completedJobs`, and `failedJobs` count accepted applications only. Rejected applications are returned in deterministic `applicationId` order.

If every application is rejected before queueing, the API returns `422 VALIDATION_ERROR` with per-application details and does not create a batch.

```json theme={null}
{
  "code": "VALIDATION_ERROR",
  "status": 422,
  "message": "No applications could be accepted for scoring",
  "retryable": false,
  "details": [
    {
      "field": "applications[app-bad].resume",
      "code": "RESUME_CORRUPTED",
      "message": "Resume file appears to be corrupted"
    }
  ],
  "traceId": "trace_..."
}
```

## Next step

Use [Get Batch Status](/embed-api/endpoints/batch-status) to poll batch progress if you need it.


## OpenAPI

````yaml POST /v1/jobs/{jobId}/scoring-batches
openapi: 3.1.0
info:
  title: Nova Embed API
  description: >-
    The Nova Embed API enables ATS platforms to generate job-scoped screening
    criteria and score applications asynchronously against those criteria.
  version: 1.0.0
  contact:
    name: Nova Support
    email: nova@dweet.com
servers:
  - url: https://embed.nova.dweet.com
    description: >-
      Environment is determined by API key prefix: sk_test_* for sandbox,
      sk_live_* for production.
security:
  - bearerAuth: []
tags:
  - name: Analytics
    description: View scoring performance, webhook health, and error breakdowns.
  - name: Criteria
    description: Generate and manage job-scoped screening criteria.
  - name: Scoring
    description: Submit applications for scoring and fetch scoring job results.
  - name: Deletion
    description: Request application or tenant deletion and poll for completion.
  - name: Criteria Library
    description: Manage tenant-scoped reusable criteria templates.
  - name: Rate Limits
    description: Check your current rate limit status.
  - name: Webhooks
    description: >-
      Events sent to your registered webhook endpoints. Verify signatures with
      HMAC-SHA256 using your webhook secret.
paths:
  /v1/jobs/{jobId}/scoring-batches:
    post:
      tags:
        - Scoring
      summary: Submit scoring batch
      description: >-
        Scoring batches are idempotent by default based on your tenant, jobId,
        and the set of applicationIds in the batch. This operation does not use
        the generic Idempotency-Key replay layer.
      operationId: submitScoringBatch
      parameters:
        - $ref: '#/components/parameters/TenantId'
        - $ref: '#/components/parameters/JobId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubmitBatchRequest'
      responses:
        '202':
          description: Accepted
          headers:
            X-RateLimit-Bucket:
              $ref: '#/components/headers/X-RateLimit-Bucket'
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubmitBatchResponse'
        '400':
          $ref: '#/components/responses/ErrorResponse'
        '401':
          $ref: '#/components/responses/ErrorResponse'
        '404':
          $ref: '#/components/responses/ErrorResponse'
        '422':
          $ref: '#/components/responses/ErrorResponse'
        '429':
          $ref: '#/components/responses/RateLimitedResponse'
        '500':
          $ref: '#/components/responses/ErrorResponse'
        '503':
          $ref: '#/components/responses/ServiceUnavailableResponse'
      x-codeSamples:
        - lang: typescript
          label: '@nova-sdk/api'
          source: |-
            import { Nova } from "@nova-sdk/api";

            const nova = new Nova({
              apiKey: "sk_test_...",
              tenantId: "acme-corp",
            });

            const result = await nova.jobs.scoringBatches.submit({
              jobId: "job_abc123",
              body: {
                jobDescription: "We are looking for a senior engineer...",
                applications: [
                  {
                    applicationId: "app_001",
                    resume: { type: "url", url: "https://example.com/resumes/application-1.pdf" },
                  },
                  {
                    applicationId: "app_002",
                    resume: { type: "url", url: "https://example.com/resumes/application-2.pdf" },
                  },
                ],
              },
            });
        - lang: bash
          label: cURL
          source: >-
            curl -X POST
            "https://embed.nova.dweet.com/v1/jobs/job_abc123/scoring-batches" \
              -H "Authorization: Bearer sk_test_..." \
              -H "X-Tenant-Id: acme-corp" \
              -H "Content-Type: application/json" \
              -d '{
              "jobDescription": "We are looking for a senior engineer...",
              "applications": [
                {
                  "applicationId": "app_001",
                  "resume": {
                    "type": "url",
                    "url": "https://example.com/resumes/application-1.pdf"
                  }
                },
                {
                  "applicationId": "app_002",
                  "resume": {
                    "type": "url",
                    "url": "https://example.com/resumes/application-2.pdf"
                  }
                }
              ]
            }'
components:
  parameters:
    TenantId:
      name: X-Tenant-Id
      in: header
      required: true
      description: Your customer identifier. Tenants are auto-provisioned on first request.
      schema:
        type: string
      example: acme-corp
    JobId:
      name: jobId
      in: path
      required: true
      description: Your job identifier (external ID).
      schema:
        type: string
  schemas:
    SubmitBatchRequest:
      type: object
      properties:
        applications:
          minItems: 1
          maxItems: 25
          type: array
          items:
            $ref: '#/components/schemas/BatchApplication'
        jobDescription:
          type: string
          minLength: 1
          maxLength: 50000
        jobTitle:
          type: string
          minLength: 1
        companyName:
          type: string
          minLength: 1
        roleKnowledge:
          type: string
          minLength: 1
          maxLength: 15000
      required:
        - applications
        - jobDescription
      additionalProperties: false
    SubmitBatchResponse:
      type: object
      required:
        - batch
        - scoringJobIds
        - acceptedApplications
        - rejectedApplications
      properties:
        batch:
          $ref: '#/components/schemas/Batch'
        scoringJobIds:
          type: array
          items:
            type: string
        acceptedApplications:
          type: array
          items:
            $ref: '#/components/schemas/BatchAcceptedApplication'
        rejectedApplications:
          type: array
          items:
            $ref: '#/components/schemas/BatchRejectedApplication'
    BatchApplication:
      type: object
      properties:
        applicationId:
          type: string
          minLength: 1
        resume:
          $ref: '#/components/schemas/ResumeInput'
        applicationData:
          $ref: '#/components/schemas/ApplicationData'
      required:
        - applicationId
        - resume
      additionalProperties: false
    Batch:
      type: object
      required:
        - id
        - jobId
        - status
        - totalJobs
        - completedJobs
        - failedJobs
        - createdAt
        - completedAt
      properties:
        id:
          type: string
        jobId:
          type: string
        status:
          $ref: '#/components/schemas/BatchStatus'
        totalJobs:
          type: integer
        completedJobs:
          type: integer
        failedJobs:
          type: integer
        createdAt:
          type: string
          format: date-time
        completedAt:
          type:
            - string
            - 'null'
          format: date-time
    BatchAcceptedApplication:
      type: object
      required:
        - applicationId
        - scoringJobId
      properties:
        applicationId:
          type: string
        scoringJobId:
          type: string
    BatchRejectedApplication:
      type: object
      required:
        - applicationId
        - error
      properties:
        applicationId:
          type: string
        error:
          type: object
          required:
            - code
            - message
            - reason
          properties:
            code:
              $ref: '#/components/schemas/ErrorCode'
            message:
              type: string
            reason:
              type:
                - string
                - 'null'
    HttpError:
      type: object
      required:
        - type
        - code
        - status
        - message
        - retryable
        - traceId
      properties:
        type:
          type: string
          description: URI reference that identifies the error type
        code:
          $ref: '#/components/schemas/ErrorCode'
        status:
          type: integer
          description: HTTP status code
        message:
          type: string
          description: Error message
        retryable:
          type: boolean
          description: When true, retrying the request may succeed
        traceId:
          type: string
          description: Trace ID for debugging
        details:
          type:
            - array
            - 'null'
          description: Field-level validation details
          items:
            type: object
            required:
              - field
              - code
              - message
            properties:
              field:
                type: string
              code:
                type: string
              message:
                type: string
    ResumeInput:
      oneOf:
        - type: object
          required:
            - type
            - url
          additionalProperties: false
          properties:
            type:
              type: string
              const: url
            url:
              type: string
              format: uri
              description: >-
                HTTPS URL to resume file (PDF, DOC, DOCX). Must be publicly
                accessible.
        - type: object
          required:
            - type
            - content
          additionalProperties: false
          properties:
            type:
              type: string
              const: text
            content:
              type: string
              minLength: 50
              description: Inline resume text (plain text or markdown, max 100KB)
      discriminator:
        propertyName: type
    ApplicationData:
      type: object
      properties:
        applicationAnswers:
          type: array
          items:
            type: object
            properties:
              question:
                type: string
                minLength: 1
              answer:
                type: string
            required:
              - question
              - answer
            additionalProperties: false
        context:
          type: string
          minLength: 1
          maxLength: 15000
      additionalProperties: false
    BatchStatus:
      type: string
      enum:
        - pending
        - completed
        - failed
    ErrorCode:
      type: string
      description: >-
        Machine-readable error code. Generated from the canonical error
        registry.
      enum:
        - UNAUTHORIZED
        - FORBIDDEN
        - VALIDATION_ERROR
        - ANSWER_MISMATCH
        - CRITERIA_INVALID
        - CRITERIA_REVISION_CONFLICT
        - NOT_FOUND
        - TENANT_NOT_FOUND
        - JOB_NOT_FOUND
        - APPLICATION_NOT_FOUND
        - QUESTION_SET_NOT_FOUND
        - CRITERIA_NOT_FOUND
        - CRITERION_NOT_FOUND
        - CRITERIA_VERSION_NOT_FOUND
        - SCORING_JOB_NOT_FOUND
        - BATCH_NOT_FOUND
        - LIBRARY_CRITERION_NOT_FOUND
        - RATE_LIMITED
        - MONTHLY_TRIAL_QUOTA_EXCEEDED
        - IDEMPOTENCY_KEY_ALREADY_USED
        - IDEMPOTENCY_REQUEST_IN_PROGRESS
        - RESUME_FETCH_FAILED
        - RESUME_CONVERSION_FAILED
        - RESUME_ENCRYPTED
        - RESUME_CORRUPTED
        - RESUME_PARSE_FAILED
        - RESUME_TOO_LARGE
        - RESUME_EMPTY
        - RESUME_URL_BLOCKED
        - AI_PROCESSING_FAILED
        - AI_GENERATION_FAILED
        - AI_SCORING_FAILED
        - MISSING_JOB_DESCRIPTION
        - TIMEOUT
        - MAX_RETRIES_EXCEEDED
        - TASK_STUCK
        - DELETION_REQUEST_NOT_FOUND
        - DELETION_REQUEST_FAILED
        - INTERNAL_ERROR
        - SERVICE_UNAVAILABLE
        - UNKNOWN
  headers:
    X-RateLimit-Bucket:
      description: Which rate limit bucket the request was classified into
      schema:
        type: string
        enum:
          - criteria_ai
          - criteria_current_reads
          - scoring_intake_batch
          - scoring_intake_single
          - read_and_ops
          - rate_limit_status
          - analytics
    X-RateLimit-Limit:
      description: Maximum requests per second for this bucket
      schema:
        type: integer
    X-RateLimit-Remaining:
      description: Requests remaining in the current 1-second window
      schema:
        type: integer
    X-RateLimit-Reset:
      description: Unix timestamp when the current window resets
      schema:
        type: integer
    Retry-After:
      description: >-
        Seconds to wait before retrying a short-window RATE_LIMITED or
        service-unavailable response whose body has retryable: true.
      schema:
        type: integer
    X-RateLimit-Degraded:
      description: >-
        Present and set to "true" when rate limiting is operating in degraded
        mode (Redis unavailable). Values in other rate limit headers are
        best-effort estimates.
      schema:
        type: string
        enum:
          - 'true'
  responses:
    ErrorResponse:
      description: Error response
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/HttpError'
    RateLimitedResponse:
      description: >-
        Too many requests. Short-window RATE_LIMITED responses include retry
        timing and rate limit headers. Monthly trial quota responses use
        MONTHLY_TRIAL_QUOTA_EXCEEDED with retryable: false.
      headers:
        Retry-After:
          $ref: '#/components/headers/Retry-After'
        X-RateLimit-Bucket:
          $ref: '#/components/headers/X-RateLimit-Bucket'
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
        X-RateLimit-Degraded:
          $ref: '#/components/headers/X-RateLimit-Degraded'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/HttpError'
    ServiceUnavailableResponse:
      description: Service temporarily unavailable
      headers:
        Retry-After:
          $ref: '#/components/headers/Retry-After'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/HttpError'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API key
      description: 'Use Authorization: Bearer sk_test_* or Authorization: Bearer sk_live_*.'

````