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

# Submit Bulk Lookup Job

> Submit a list of (first name, last name, domain) tuples for bulk email lookup. Returns a job ID immediately. Poll GET /v1/bulk-lookup/{job_id} to track progress.

Use this endpoint to submit a list of people (first name, last name, and company domain) for asynchronous email lookup. The API accepts your list, deduplicates it, charges your credit balance upfront, and returns a `job_id` immediately. Lookups happen in the background — poll [GET /v1/bulk-lookup/\{job\_id}](/docs/api-reference/bulk-lookup-status) to track progress, then fetch results via [GET /v1/bulk-lookup/\{job\_id}/results](/docs/api-reference/bulk-lookup-results) when the job is complete.

## Deduplication and async processing

OrbiSearch deduplicates your list before processing. If you submit 600 tuples but 100 are duplicates (matched case-insensitively on first name + last name + domain), `total_rows` will be `500` and you will only be charged for 500 lookups.

Because bulk jobs run asynchronously, this endpoint returns immediately after accepting the job. Use the returned `job_id` to poll [GET /v1/bulk-lookup/\{job\_id}](/docs/api-reference/bulk-lookup-status) until the `status` field reaches `completed`. Then fetch results via [GET /v1/bulk-lookup/\{job\_id}/results](/docs/api-reference/bulk-lookup-results).

## Pricing and refund behaviour

Each unique row costs `1 credit`, charged upfront at submission time. Every returned row is charged. Refunds are issued only when OrbiSearch infrastructure cannot accept or process the submission itself — in that case the upfront charge is reversed and no job is created.

If your account has insufficient credits for the deduplicated row count, the request fails with `403 Forbidden`.

## Limits

* Maximum `10,000` rows per submission. Larger lists must be split across multiple jobs.
* Each row's `first_name`, `last_name`, and `domain` are required and capped at 255 characters.

## Rate limits

This endpoint shares the `20` requests per second per API key limit with the rest of the `/v1/*` API. Exceeding it returns a `429 Too Many Requests` response. See [errors](/docs/api-reference/errors) for how to handle rate limit responses.


## OpenAPI

````yaml POST /v1/bulk-lookup
openapi: 3.1.0
info:
  title: OrbiSearch Public API
  version: 1.0.0
  description: >-
    Email verification API for developers and agents. [Get your API key
    →](https://orbisearch.com/dashboard/api-keys)


    **Rate limiting:** requests are limited per API key (20 requests per second
    by default). Every response includes `X-RateLimit-Limit`,
    `X-RateLimit-Remaining` and `X-RateLimit-Reset` headers describing the
    current per-key window so clients can self-throttle; `429` responses also
    include a `Retry-After` header with the suggested backoff in seconds.
  contact:
    name: Get API Key
    url: https://orbisearch.com/dashboard/api-keys
servers:
  - url: https://api.orbisearch.com
    description: OrbiSearch Public API
security:
  - ApiKeyAuth: []
paths:
  /v1/bulk-lookup:
    post:
      tags:
        - Public API v1
      summary: Submit Bulk Lookup
      description: >-
        Submit a list of (first_name, last_name, domain) tuples for asynchronous

        bulk email lookup. Rows are deduplicated (case-insensitive) before

        billing; credits are deducted upfront at 1 credit per unique row.


        Returns a `job_id` immediately. Poll `GET /v1/bulk-lookup/{job_id}`
        until

        `status` reaches `complete`, then fetch results via

        `GET /v1/bulk-lookup/{job_id}/results`.


        Every returned row is charged. Refunds are issued only when OrbiSearch

        infrastructure cannot accept or process the submission itself (the

        upfront charge is reversed in that case).


        Rate limit: 20 requests per second per API key, shared with
        `/v1/verify`,

        `/v1/bulk`, and `/v1/email-lookup`.
      operationId: submit_bulk_lookup_v1_bulk_lookup_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkLookupSubmitRequest'
        required: true
      responses:
        '202':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BulkLookupSubmitResponse'
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the current per-API-key window.
              schema:
                type: integer
                examples:
                  - 20
            X-RateLimit-Remaining:
              description: Requests remaining in the current per-API-key window.
              schema:
                type: integer
                examples:
                  - 13
            X-RateLimit-Reset:
              description: Unix timestamp (seconds) at which the current window resets.
              schema:
                type: integer
                examples:
                  - 1751700000
        '401':
          description: Invalid or missing API key
          content:
            application/json:
              example:
                detail: API key required in X-API-Key header
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
        '403':
          description: Insufficient credits
          content:
            application/json:
              example:
                detail: Insufficient credits. You have 0.15 credits but need 0.2.
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the current per-API-key window.
              schema:
                type: integer
                examples:
                  - 20
            X-RateLimit-Remaining:
              description: Requests remaining in the current per-API-key window.
              schema:
                type: integer
                examples:
                  - 13
            X-RateLimit-Reset:
              description: Unix timestamp (seconds) at which the current window resets.
              schema:
                type: integer
                examples:
                  - 1751700000
        '422':
          description: Invalid request parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
              example:
                detail: >-
                  Invalid request body field '0': Input should be a valid
                  string.
                errors:
                  - loc: body.0
                    msg: >-
                      Invalid request body field '0': Input should be a valid
                      string.
                    type: string_type
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the current per-API-key window.
              schema:
                type: integer
                examples:
                  - 20
            X-RateLimit-Remaining:
              description: Requests remaining in the current per-API-key window.
              schema:
                type: integer
                examples:
                  - 13
            X-RateLimit-Reset:
              description: Unix timestamp (seconds) at which the current window resets.
              schema:
                type: integer
                examples:
                  - 1751700000
        '429':
          description: Rate limit exceeded
          headers:
            Retry-After:
              description: >-
                Seconds the client should wait before retrying. Computed from
                the remaining rate-limit window (typically 1 for the per-second
                limit, longer when the limit is exceeded by 3x or more); for
                endpoints with a daily quota, seconds until the quota resets.
              schema:
                type: integer
                examples:
                  - 1
            X-RateLimit-Limit:
              description: Maximum requests allowed in the current per-API-key window.
              schema:
                type: integer
                examples:
                  - 20
            X-RateLimit-Remaining:
              description: Requests remaining in the current per-API-key window.
              schema:
                type: integer
                examples:
                  - 13
            X-RateLimit-Reset:
              description: Unix timestamp (seconds) at which the current window resets.
              schema:
                type: integer
                examples:
                  - 1751700000
          content:
            application/json:
              example:
                detail: >-
                  Rate limit exceeded. Maximum 20 requests per second per API
                  key. Contact us to discuss higher limits.
                code: rate_limited
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
        '503':
          description: Email-lookup service not configured
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
              example:
                detail: Email lookup is not available in this environment
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the current per-API-key window.
              schema:
                type: integer
                examples:
                  - 20
            X-RateLimit-Remaining:
              description: Requests remaining in the current per-API-key window.
              schema:
                type: integer
                examples:
                  - 13
            X-RateLimit-Reset:
              description: Unix timestamp (seconds) at which the current window resets.
              schema:
                type: integer
                examples:
                  - 1751700000
      security:
        - ApiKeyAuth: []
components:
  schemas:
    BulkLookupSubmitRequest:
      properties:
        input:
          items:
            $ref: '#/components/schemas/BulkLookupInputRow'
          type: array
          maxItems: 10000
          minItems: 1
          title: Input
          description: >-
            List of (first_name, last_name, domain) tuples to look up. Duplicate
            tuples are deduplicated before billing. Maximum 10,000 rows per
            submission.
      type: object
      required:
        - input
      title: BulkLookupSubmitRequest
      description: Submission payload for POST /v1/bulk-lookup.
      example:
        input:
          - domain: acme.com
            first_name: Jane
            last_name: Doe
          - domain: bigcorp.io
            first_name: John
            last_name: Smith
    BulkLookupSubmitResponse:
      properties:
        job_id:
          type: string
          format: uuid
          title: Job Id
          description: >-
            Unique job identifier. Pass this to GET /v1/bulk-lookup/{job_id} to
            poll status.
          examples:
            - 123e4567-e89b-12d3-a456-426614174000
        status:
          type: string
          enum:
            - submitted
          const: submitted
          title: Status
          description: Submission acknowledgement status.
          examples:
            - submitted
        total_rows:
          type: integer
          title: Total Rows
          description: Number of unique rows submitted after deduplication.
          examples:
            - 500
        credits_consumed:
          type: integer
          title: Credits Consumed
          description: >-
            Credits deducted for this submission. Equals total_rows (1 credit
            per unique row).
          examples:
            - 500
      type: object
      required:
        - job_id
        - status
        - total_rows
        - credits_consumed
      title: BulkLookupSubmitResponse
      description: Response when submitting a bulk lookup job.
      example:
        credits_consumed: 500
        job_id: 123e4567-e89b-12d3-a456-426614174000
        status: submitted
        total_rows: 500
    ApiErrorResponse:
      properties:
        detail:
          type: string
          title: Detail
          description: Human-readable description of what went wrong.
          examples:
            - API key required in X-API-Key header
        code:
          anyOf:
            - type: string
            - type: 'null'
          title: Code
          description: >-
            Stable machine-readable error code, present on conditions a client
            may want to branch on (for example `rate_limited` for the per-second
            limit versus `daily_quota_exceeded` for the daily cap). Absent on
            errors that need no further disambiguation.
          examples:
            - daily_quota_exceeded
        errors:
          anyOf:
            - items:
                $ref: '#/components/schemas/ValidationErrorDetail'
              type: array
            - type: 'null'
          title: Errors
          description: >-
            Individual validation failures, one entry per invalid parameter or
            field. Present only on 422 responses; when the request has a single
            problem, `detail` carries the same message. Absent on all other
            error codes.
      type: object
      required:
        - detail
      title: ApiErrorResponse
      description: Error response body.
    BulkLookupInputRow:
      properties:
        first_name:
          type: string
          maxLength: 64
          title: First Name
          description: >-
            Person's first name. Optional individually — provide at least one of
            first or last name.
          default: ''
          examples:
            - Jane
        last_name:
          type: string
          maxLength: 64
          title: Last Name
          description: >-
            Person's last name. Optional individually — provide at least one of
            first or last name.
          default: ''
          examples:
            - Doe
        domain:
          type: string
          maxLength: 253
          minLength: 3
          title: Domain
          description: Company domain to search within.
          examples:
            - acme.com
      type: object
      required:
        - domain
      title: BulkLookupInputRow
      description: One name+domain tuple submitted for bulk lookup.
      example:
        domain: acme.com
        first_name: Jane
        last_name: Doe
    ValidationErrorDetail:
      properties:
        loc:
          type: string
          title: Loc
          description: >-
            Where in the request the problem is, as a dot-separated path (e.g.
            `query.email`, `body.0`).
          examples:
            - query.email
        msg:
          type: string
          title: Msg
          description: Human-readable description of this validation error.
          examples:
            - 'Missing required query parameter: email.'
        type:
          type: string
          title: Type
          description: >-
            Machine-readable error category (e.g. `missing`, `less_than_equal`,
            `string_too_long`).
          examples:
            - missing
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationErrorDetail
      description: One request-validation failure.
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      description: API key for authentication
      in: header
      name: X-API-Key

````