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

# Dial the next block

> For a batch dialling its rows in blocks (`blockSize` set at create):
the runner claims only rows up to the active block's ceiling, and
nothing beyond it is dialled until someone asks. This raises the
ceiling by one block. Refused while the current block is still dialing,
so the outcomes it exists to show are in before the next one starts.




## OpenAPI

````yaml /openapi/api-public-v1.yaml post /batches/{id}/blocks/next
openapi: 3.0.3
info:
  title: Vodex API (v1)
  description: >
    The **public Vodex `/v1` REST API** — everything a customer's own systems

    integrate with: assistants, telephony (numbers, trunks, carrier

    integrations), calls and recordings, batch dialing, the SMS channel, and

    outbound webhooks.


    This is deliberately a **subset**. Account and console-only routes

    (`/v1/auth/*`, `/v1/api-keys`, `/v1/usage`), platform provisioning

    (`/v1/platform/*`), Vodex support operations, and endpoints other systems

    call inward (carrier delivery receipts, the agent worker, cron) are not

    part of the published surface and are not documented here.


    The **data plane** (LiveKit SFU + SIP + the agent worker) is not an HTTP

    API and is not described here: a call reaches the worker over LiveKit, with

    its config carried in participant metadata or read from the config snapshot

    this API publishes.


    ## Authentication


    | Credential | Sent as | Scope |

    |---|---|---|

    | **Tenant API key** | `Authorization: Bearer vdx_live_…` | One customer,
    full access — the credential for everything in this document |


    Mint an API key in the console (**Settings → API keys**). The plaintext is

    shown **once**, by the call that creates it, and no endpoint reads one back

    — a lost key is replaced, not recovered.


    Every route here also answers a signed-in console session, because the

    console is built on this same API. That is **not** an integration

    credential and is deliberately not described as one: it is the console's

    own cookie, it carries a role an API key never has, and it is free to

    change. Integrate with `vdx_live_`.


    ## Customers and tenants


    One thing, two words, and they are not interchangeable:


    - **Customer** is the product word — what a human calls the account, and
      what the console shows you.
    - **Tenant** is the same thing's identity on the wire and in storage:
      `tenantId` on every response.

    **A *workspace* is a third thing, and not a synonym for either.** Tenancy

    is mapped at the customer level deliberately: integrations (carrier, SMS,

    provider credentials) live above the workspaces that use them, so mapping

    workspaces to tenants would fragment one customer's telephony across

    tenants that then have to share credentials. A workspace is therefore a

    **label inside the tenant** (`externalWorkspaceRef`) — for filtering and

    attribution, never isolation. Anything that must not be shared between one

    customer's workspaces needs its own tenant.


    ## Tenancy


    There is **no tenant parameter**. Every tenant-scoped route derives its

    tenant from the credential and binds it for the whole request, so a caller

    cannot ask for another tenant's data by changing a query string. An id that

    belongs to somebody else answers `404`, never `403` — "no such call" is the

    only thing worth confirming.


    ## Response shapes


    Resources are returned **flat**, at the top level (`{ "id": "…", … }`) —

    there is no envelope object. Collections vary by age of the endpoint:


    - Newer lists are `{ "<plural>": [ … ], "total": n, "limit": n, "offset": n
    }`
      (`calls`, `batches`, `rows`, `attempts`, `messages`).
    - Older lists return a **bare JSON array** (`/v1/phone-numbers`,
      `/v1/sip-trunks`, `/v1/integrations`, `/v1/carriers`,
      `/v1/console/assistants`, `/v1/sms/configurations`).

    Deletes and side-effecting no-content operations return `{ "ok": true }`.


    ## Errors


    ```json

    { "error": "human-readable message" }

    ```


    A flat string, not a coded object — HTTP status is the machine signal.

    The one exception is quota exhaustion (`402`), which adds a stable

    `code: "quota_exhausted"` plus the counters the console renders.


    ## Pagination


    `?limit=` and `?offset=`, with `total` in the body. Defaults and ceilings

    differ per endpoint (calls 25/100, batch rows 50/500, attempts 100/500) and

    are stated on each operation.


    ## Conventions


    - **Phone numbers** are E.164 strings (`+14155551234`); `+91…` numbers are
      served from Mumbai, `+1…` from us-central1.
    - **Money** is a JSON number of **USD** (`costUsd`), not a decimal string.

    - **Timestamps** are ISO‑8601 UTC strings, except the calls list, which
      reports `mtime` / `startedAt` as epoch **milliseconds** and durations as
      **milliseconds**.
    - **Ids** are unprefixed: batches, rows, attempts and SMS rows are UUIDs;
      a call id is its LiveKit room name (`call-…`, or `console-…` for web
      calls); a phone number's id is `num-<digits>`; a trunk's is `trunk-…`.
    - **Secrets** (`vdx_live_…`, `whsec_…`) are returned exactly once, by the
      call that mints them. No endpoint reads one back — carrier and provider
      credentials are stored in Secret Manager and echoed only as a
      non-reversible fingerprint.
    - **Idempotency**: `POST /v1/sms` and `POST /v1/batches` **require** an
      `Idempotency-Key` header. Only successful (2xx) responses are replayed;
      a failed attempt releases the key so a corrected retry can reuse it.
  version: 1.0.0
  contact:
    name: Vodex Platform
    url: https://vodex.ai
  license:
    name: Proprietary
    url: https://vodex.ai/terms
servers:
  - url: https://apiv2.vodex.ai/v1
    description: Production
security:
  - ApiKeyBearer: []
tags:
  - name: Assistants
    description: Assistant configurations (the agent's engine, prompt, slots, tools).
  - name: Console
    description: Reference data (model catalog, voices) and the web-call token.
  - name: Usage
    description: Minute usage against the plan.
  - name: Calls
    description: Place calls, read the call log, fetch traces and recordings.
  - name: Phone Numbers
    description: Number inventory and assistant mapping.
  - name: SIP Trunks
    description: Customer-owned (BYO) SIP trunks.
  - name: Carriers
    description: Carrier registry — what can be connected, and how.
  - name: Integrations
    description: Connected carrier accounts and their numbers.
  - name: Batches
    description: Batch dialing — lists in, calls out.
  - name: Number Rotation
    description: Per-number spacing, daily caps, and cooldown.
  - name: Callbacks
    description: >-
      "Call me Tuesday afternoon" — appointments booked mid-call, and dialed
      later.
  - name: SMS
    description: SMS configurations, credentials, preview, send, and message log.
  - name: Webhooks
    description: Outbound webhook configuration and delivery records.
  - name: Tenants
    description: Recording retention.
  - name: Contacts
    description: >-
      The people a tenant calls — records, channels, custom attributes, files,
      and CSV import.
  - name: Audiences
    description: >-
      Saved filters over contacts. Stored as a filter tree, never a frozen id
      list.
  - name: Campaigns
    description: An audience plus an assistant, executed as a batch.
  - name: Do Not Contact
    description: The address suppression list, and the person-level decision beside it.
paths:
  /batches/{id}/blocks/next:
    post:
      tags:
        - Batches
      summary: Dial the next block
      description: |
        For a batch dialling its rows in blocks (`blockSize` set at create):
        the runner claims only rows up to the active block's ceiling, and
        nothing beyond it is dialled until someone asks. This raises the
        ceiling by one block. Refused while the current block is still dialing,
        so the outcomes it exists to show are in before the next one starts.
      operationId: runNextBatchBlock
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '202':
          description: The next block was cleared to dial.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Batch'
                  - type: object
                    properties:
                      blocks:
                        type: array
                        items:
                          $ref: '#/components/schemas/BatchBlock'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: >-
            Not run in blocks, cancelled, the current block is still dialing, or
            every block has been dialed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    Batch:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        status:
          type: string
          enum:
            - running
            - paused
            - completed
            - cancelled
            - failed
        runNo:
          type: integer
        assistantId:
          type: string
          format: uuid
          description: >-
            The assistant's uuid, shown on its configure page in the console.
            Names and slugs are not accepted.
        concurrency:
          type: integer
        retry:
          $ref: '#/components/schemas/RetryPolicy'
        window:
          $ref: '#/components/schemas/CallingWindow'
        suppress:
          type: array
          items:
            type: string
        blockSize:
          type: integer
          nullable: true
          description: >-
            Rows per block, or null to dial the whole list at once. Set at
            create.
        activeBlock:
          type: integer
          description: >-
            The highest block cleared to dial (1-based); only meaningful with a
            blockSize.
        createdAt:
          type: string
          format: date-time
          nullable: true
        startedAt:
          type: string
          format: date-time
          nullable: true
        completedAt:
          type: string
          format: date-time
          nullable: true
        counts:
          type: object
          additionalProperties:
            type: integer
          description: Row counts by status, plus `total`.
    BatchBlock:
      type: object
      description: One block of a ranged batch — a slice of its rows by upload position.
      properties:
        blockNo:
          type: integer
          description: 1-based position of this block.
        rangeStart:
          type: integer
          description: First row position in the block (1-based, inclusive).
        rangeEnd:
          type: integer
          description: Last row position in the block (inclusive).
        contacts:
          type: integer
          description: Rows in this block.
        status:
          type: string
          enum:
            - pending
            - running
            - completed
        counts:
          type: object
          additionalProperties:
            type: integer
          description: Row counts by status within the block, plus `total`.
    Error:
      type: object
      properties:
        error:
          type: string
          example: not found
    RetryPolicy:
      type: object
      properties:
        'on':
          type: array
          items:
            type: string
          description: End reasons worth retrying (e.g. `no_answer`, `busy`).
        attempts:
          type: integer
          minimum: 0
          maximum: 10
        backoffMinutes:
          type: number
          minimum: 1
          maximum: 10080
    CallingWindow:
      type: object
      nullable: true
      description: When this batch may dial — outside it, rows wait rather than fail.
      properties:
        timezone:
          type: string
          example: America/New_York
        start:
          type: string
          example: '09:00'
        end:
          type: string
          example: '20:00'
        days:
          type: array
          items:
            type: integer
            minimum: 0
            maximum: 6
  responses:
    BadRequest:
      description: Validation failed.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: No usable credential.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: >-
        No such resource — or it belongs to another tenant, which looks the
        same.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    ApiKeyBearer:
      type: http
      scheme: bearer
      description: 'Tenant API key (`vdx_live_…`) as `Authorization: Bearer`.'

````