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

# 💎 Proposal Timing

> Returns when an entity's proposals reached one beaconcha.in node, aggregated over an evaluation window, next to the same figures for the whole network over the same window. Optionally scope to a sub-entity; omit `sub_entity` for the whole entity.

From the Glamsterdam hard fork on, the proposer publishes its own block, so the time at which a block reaches our node follows the proposer's setup; the winning builder may also forward the block, which can make it arrive earlier. The figures are one node's view: each node receives a block at its own time, and a proposer's network position gives it a stable offset to our node, so the figures show when our node saw a block, not why it arrived then. The time is when our node received the block over the peer-to-peer gossip network, relative to the slot start; a block our node imported another way has no time and is counted separately.

`publish_time.median_slot_offset_vs_network_ms` compares each proposal with the network median of the same hour of slot start, so a slow hour at our node does not count against the entity. The network median includes the entity's own proposals, which pulls the offset of a large entity toward zero.

The attestation deadline is `ATTESTATION_DUE_BPS_GLOAS` of the slot duration, 3000 ms at 12-second slots. Fork choice counts a block as timely only when it arrives before the deadline, and each node judges by its own arrival time, so a count at or after the deadline describes our node's view, not the chain's verdict. A block that our node received but the chain did not include is counted in `not_included_count`; the arrival time alone does not show why the chain did not include it.

Only finalized slots count, and the window never reaches before the fork. The window ends at the last slot for which both the included and the missed proposals are recorded, at most the last slot of the epoch before the head; `range` returns the window evaluated. When no slot of the window has a verdict yet, `range` returns the requested window, and in the fork's own epoch, before any slot after the fork can have a verdict, the first slot after the fork. Medians and percentiles are exact, not interpolated: for an even count the median is the upper of the two middle values. A median needs at least 20 proposals seen on gossip and a 90th percentile at least 50; below that the field is null and the counts remain.

Combine this endpoint with others for deeper insights:
- Each proposal of a set of validators, with its own publish time: [v2/ethereum/validators/proposal-slots](/api-reference/ethereum/validators/proposal-slots)
- The entities and sub-entities to pass: [v2/ethereum/entities](/api-reference/ethereum/entities/overview), [v2/ethereum/entity/sub-entities](/api-reference/ethereum/entity/sub-entities)
- Before the fork, proposal timing measured from relay bids, which is not comparable with this measure: [v2/ethereum/entity/mev-timing](/api-reference/ethereum/entity/mev-timing)

**Premium Endpoint:** This endpoint requires a Scale or Enterprise plan.


> [!WARNING]
>
> **Experimental.** This endpoint returns data only on chains past the Glamsterdam hard fork. Hoodi forks first; mainnet returns `404` until it forks. The request and response may change before the mainnet release. See [Glamsterdam API](https://docs.beaconcha.in/api/glamsterdam.md).


## OpenAPI

````yaml /v3/bundled.yaml post /api/v2/ethereum/entity/proposal-timing
openapi: 3.0.4
info:
  title: External Service API
  version: 1.0.3
servers:
  - url: https://beaconcha.in
    description: Production API
security:
  - ApiKeyAuth: []
paths:
  /api/v2/ethereum/entity/proposal-timing:
    post:
      tags:
        - Entities
      summary: 💎 Proposal Timing
      description: >
        Returns when an entity's proposals reached one beaconcha.in node,
        aggregated over an evaluation window, next to the same figures for the
        whole network over the same window. Optionally scope to a sub-entity;
        omit `sub_entity` for the whole entity.


        From the Glamsterdam hard fork on, the proposer publishes its own block,
        so the time at which a block reaches our node follows the proposer's
        setup; the winning builder may also forward the block, which can make it
        arrive earlier. The figures are one node's view: each node receives a
        block at its own time, and a proposer's network position gives it a
        stable offset to our node, so the figures show when our node saw a
        block, not why it arrived then. The time is when our node received the
        block over the peer-to-peer gossip network, relative to the slot start;
        a block our node imported another way has no time and is counted
        separately.


        `publish_time.median_slot_offset_vs_network_ms` compares each proposal
        with the network median of the same hour of slot start, so a slow hour
        at our node does not count against the entity. The network median
        includes the entity's own proposals, which pulls the offset of a large
        entity toward zero.


        The attestation deadline is `ATTESTATION_DUE_BPS_GLOAS` of the slot
        duration, 3000 ms at 12-second slots. Fork choice counts a block as
        timely only when it arrives before the deadline, and each node judges by
        its own arrival time, so a count at or after the deadline describes our
        node's view, not the chain's verdict. A block that our node received but
        the chain did not include is counted in `not_included_count`; the
        arrival time alone does not show why the chain did not include it.


        Only finalized slots count, and the window never reaches before the
        fork. The window ends at the last slot for which both the included and
        the missed proposals are recorded, at most the last slot of the epoch
        before the head; `range` returns the window evaluated. When no slot of
        the window has a verdict yet, `range` returns the requested window, and
        in the fork's own epoch, before any slot after the fork can have a
        verdict, the first slot after the fork. Medians and percentiles are
        exact, not interpolated: for an even count the median is the upper of
        the two middle values. A median needs at least 20 proposals seen on
        gossip and a 90th percentile at least 50; below that the field is null
        and the counts remain.


        Combine this endpoint with others for deeper insights:

        - Each proposal of a set of validators, with its own publish time:
        [v2/ethereum/validators/proposal-slots](/api-reference/ethereum/validators/proposal-slots)

        - The entities and sub-entities to pass:
        [v2/ethereum/entities](/api-reference/ethereum/entities/overview),
        [v2/ethereum/entity/sub-entities](/api-reference/ethereum/entity/sub-entities)

        - Before the fork, proposal timing measured from relay bids, which is
        not comparable with this measure:
        [v2/ethereum/entity/mev-timing](/api-reference/ethereum/entity/mev-timing)


        **Premium Endpoint:** This endpoint requires a Scale or Enterprise plan.
      operationId: GetEntityProposalTiming
      requestBody:
        $ref: '#/components/requestBodies/entityProposalTiming'
      responses:
        '200':
          $ref: '#/components/responses/EntityProposalTiming'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '405':
          $ref: '#/components/responses/MethodNotAllowed'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultError'
components:
  requestBodies:
    entityProposalTiming:
      x-go-name: EntityProposalTimingRequestBody
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/EntityProposalTimingRequest'
          example:
            entity: Lido
            range:
              evaluation_window: 30d
            chain: hoodi
  responses:
    EntityProposalTiming:
      description: Successful response.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/EntityProposalTiming.Container'
    BadRequest:
      description: Bad Request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Bad request. Please check your input and try again.
    Unauthorized:
      description: Unauthorized
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Unauthorized. Please provide a valid API key.
    Forbidden:
      description: Forbidden
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: >-
              endpoint not allowed for your subscription tier. upgrade your
              subscription at https://beaconcha.in/pricing.
    NotFound:
      description: Not Found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: The requested resource was not found.
    MethodNotAllowed:
      description: Method Not Allowed
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: 'method not allowed: GET. all public API endpoints use POST.'
    RateLimitExceeded:
      description: Rate Limit Exceeded
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Rate limit exceeded. Please try again later.
    InternalServerError:
      description: Internal Server Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: internal server error. please try again later.
    DefaultError:
      description: An unexpected error response.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: An unexpected error occurred.
  schemas:
    EntityProposalTimingRequest:
      type: object
      properties:
        chain:
          $ref: '#/components/schemas/Chain'
        entity:
          allOf:
            - $ref: '#/components/schemas/EntityName'
          description: >-
            The name of the entity to aggregate the proposals of (e.g. "Lido",
            "Coinbase"). Matching is case-sensitive; use the exact name as
            returned by the entities overview endpoint. An entity without
            proposals in the window returns zero counts.
        sub_entity:
          $ref: '#/components/schemas/SubEntityName'
          description: >-
            Optional sub-entity to scope the figures. Omit or pass an empty
            string to aggregate the whole entity. Matching is case-sensitive;
            use the exact name as returned by the sub-entities overview
            endpoint.
        range:
          $ref: '#/components/schemas/NamedProposalTimingEvaluationWindow'
      required:
        - entity
        - range
    EntityProposalTiming.Container:
      type: object
      description: >-
        Response containing when the entity's proposals reached one beaconcha.in
        node over the evaluation window.
      properties:
        data:
          $ref: '#/components/schemas/EntityProposalTiming.Data'
        range:
          $ref: '#/components/schemas/ResultRange'
      required:
        - data
        - range
    Error:
      type: object
      properties:
        error:
          type: string
    Chain:
      type: string
      enum:
        - mainnet
        - hoodi
      default: mainnet
      description: The Ethereum chain to query.
    EntityName:
      type: string
      description: The name of the entity (e.g., "Lido", "Coinbase").
    SubEntityName:
      type: string
      description: The name of the sub-entity.
    NamedProposalTimingEvaluationWindow:
      type: object
      title: Fixed Window
      properties:
        evaluation_window:
          $ref: '#/components/schemas/ProposalTimingEvaluationWindow'
      required:
        - evaluation_window
    EntityProposalTiming.Data:
      type: object
      description: >-
        Proposal timing of the entity over the evaluation window. The window
        ends at the last finalized slot and starts no earlier than the
        Glamsterdam hard fork.
      properties:
        evaluation_window:
          $ref: '#/components/schemas/ProposalTimingEvaluationWindow'
        publish_time:
          $ref: '#/components/schemas/EntityProposalTiming.PublishTime'
      required:
        - evaluation_window
        - publish_time
    ResultRange:
      type: object
      description: >
        The time span actually covered by the returned results — from the first
        to the last matching data point — specified in slots, epochs, and Unix
        timestamps.


        This reflects the data that was found, not the range that was queried.
        When the response is `200` but no data is found, it falls back to the
        requested range, or to the full available history if no range was given.
        Some endpoints answer `404` instead when no data is found.


        For arbitrary (custom) time-range queries the queried range is expanded
        outward to whole UTC days, so the covered range may be wider than
        requested. As stated above, the reported range still reflects the data
        that was actually found — a touched UTC day with no data for the
        selected validators will not extend it.
      properties:
        slot:
          $ref: '#/components/schemas/SlotRange'
        epoch:
          $ref: '#/components/schemas/EpochRange'
        timestamp:
          $ref: '#/components/schemas/TimeRange'
      required:
        - slot
        - epoch
        - timestamp
    ProposalTimingEvaluationWindow:
      type: string
      enum:
        - 24h
        - 7d
        - 30d
      x-enum-varnames:
        - ProposalTimingWindow24h
        - ProposalTimingWindow7d
        - ProposalTimingWindow30d
      example: 30d
      description: >
        The rolling window to aggregate the proposals over. The window ends at
        the last finalized slot, moves every epoch (~6.4 minutes) and starts no
        earlier than the Glamsterdam hard fork.


        - `24h`: Last 24 hours (rolling)

        - `7d`: Last 7 days (rolling)

        - `30d`: Last 30 days (rolling)
    EntityProposalTiming.PublishTime:
      type: object
      description: >-
        When the entity's proposal blocks first reached one beaconcha.in node
        over the peer-to-peer gossip network, next to the whole network over the
        same window.
      properties:
        attestation_deadline_ms:
          type: integer
          description: >-
            The attestation deadline in milliseconds after the slot start,
            `ATTESTATION_DUE_BPS_GLOAS` of the slot duration, which is 3000 at
            12-second slots. Fork choice counts a block as timely only when it
            arrives before this deadline.
        median_slot_offset_vs_network_ms:
          type: integer
          nullable: true
          description: >-
            The median, over the entity's proposals seen on gossip, of each
            proposal's `slot_offset_ms` minus the network median of the same
            hour of slot start. Negative means the entity's blocks reached our
            node earlier than the network's. The network median includes the
            entity's own proposals. Null when `entity.seen_on_gossip_count` is
            below 20.
        entity:
          $ref: '#/components/schemas/PublishTimeAggregate'
        network:
          $ref: '#/components/schemas/PublishTimeAggregate'
      required:
        - attestation_deadline_ms
        - median_slot_offset_vs_network_ms
        - entity
        - network
    SlotRange:
      type: object
      properties:
        start:
          $ref: '#/components/schemas/Slot'
        end:
          $ref: '#/components/schemas/Slot'
      required:
        - start
        - end
    EpochRange:
      type: object
      properties:
        start:
          $ref: '#/components/schemas/Epoch'
        end:
          $ref: '#/components/schemas/Epoch'
      required:
        - start
        - end
    TimeRange:
      type: object
      properties:
        start:
          $ref: '#/components/schemas/timestamp'
        end:
          $ref: '#/components/schemas/timestamp'
      required:
        - start
        - end
    PublishTimeAggregate:
      type: object
      description: >-
        When a set of proposals reached one beaconcha.in node. A proposal counts
        once its slot is finalized, if the chain included its block or our node
        received a block for it. A missed slot for which our node received no
        block was never published and does not count.
      properties:
        proposal_count:
          type: integer
          minimum: 0
          description: >-
            Proposals that count. The sum of `seen_on_gossip_count`,
            `not_seen_on_gossip_count`, `not_observed_count` and
            `multiple_blocks_seen_count`.
        seen_on_gossip_count:
          type: integer
          minimum: 0
          description: >-
            Proposals whose block our node received over the peer-to-peer gossip
            network. Only these have a time, and the medians and the percentile
            use only them.
        median_slot_offset_ms:
          type: integer
          nullable: true
          description: >-
            Median milliseconds after the slot start at which our node received
            the blocks over gossip, by our node's clock. Null when
            `seen_on_gossip_count` is below 20.
        p90_slot_offset_ms:
          type: integer
          nullable: true
          description: >-
            90th percentile of the milliseconds after the slot start at which
            our node received the blocks over gossip. Null when
            `seen_on_gossip_count` is below 50.
        seen_after_attestation_deadline_count:
          type: integer
          minimum: 0
          description: >-
            Proposals whose block our node received at or after the attestation
            deadline. It describes when our node received the block, not whether
            the chain counted the block as timely.
        not_seen_on_gossip_count:
          type: integer
          minimum: 0
          description: >-
            Proposals whose block our node imported without receiving it over
            gossip, for example while it was syncing or before it had verified
            the parent block's execution payload. The usual cause is our own
            node, not the proposer.
        not_observed_count:
          type: integer
          minimum: 0
          description: >-
            Included proposals of which our node has no record, for example
            during an outage of our node.
        multiple_blocks_seen_count:
          type: integer
          minimum: 0
          description: >-
            Proposals for whose slot our node received more than one block. They
            have no time, because the figures cannot tell which of the blocks
            the chain included.
        not_included_count:
          type: integer
          minimum: 0
          description: >-
            Proposals whose block our node received but the chain did not
            include, as an orphaned block or for a slot the explorer shows as
            missed. They count in the other figures as well. The arrival time
            alone does not show why the chain did not include a block.
        not_included_seen_after_attestation_deadline_count:
          type: integer
          minimum: 0
          description: >-
            The part of `not_included_count` whose block our node received at or
            after the attestation deadline.
      required:
        - proposal_count
        - seen_on_gossip_count
        - median_slot_offset_ms
        - p90_slot_offset_ms
        - seen_after_attestation_deadline_count
        - not_seen_on_gossip_count
        - not_observed_count
        - multiple_blocks_seen_count
        - not_included_count
        - not_included_seen_after_attestation_deadline_count
    Slot:
      type: integer
      minimum: 0
      description: Slot by number.
    Epoch:
      type: integer
      minimum: 0
    timestamp:
      type: integer
      minimum: 0
  securitySchemes:
    ApiKeyAuth:
      type: http
      scheme: bearer
      description: >-
        Authorization header with value: Bearer YOUR_TOKEN. Refer to the [API
        Keys](/api/overview#api-keys) section to create your API key.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.