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

# ListLeadNextActionsAPI mirrors the erdo_list_lead_next_actions MCP tool.




## OpenAPI

````yaml /api/openapi.json get /v1/lead-next-actions
openapi: 3.0.0
info:
  title: Erdo API
  description: >-
    Erdo's REST API: query and write datasets, run agents, manage threads,
    integrations, pages, evals, workstreams, experiments, and bounded outreach.
    Authenticate with a Bearer API key (erdo_api_...) or scoped token
    (erdo_token_...).
  version: '2026-09-22'
servers:
  - url: https://api.erdo.ai
    description: Production
security:
  - bearerAuth: []
paths:
  /v1/lead-next-actions:
    get:
      summary: |
        ListLeadNextActionsAPI mirrors the erdo_list_lead_next_actions MCP tool.
      operationId: GET:mcp.ListLeadNextActionsAPI
      parameters:
        - allowEmptyValue: true
          description: |
            Dataset narrows to one lead dataset, by slug or id.
          explode: true
          in: query
          name: dataset
          required: false
          schema:
            type: string
          style: form
        - allowEmptyValue: true
          description: |
            Status narrows to one status, e.g. pending\_approval.
          explode: true
          in: query
          name: status
          required: false
          schema:
            type: string
          style: form
        - allowEmptyValue: true
          description: |
            Priority narrows to high, medium or low.
          explode: true
          in: query
          name: priority
          required: false
          schema:
            type: string
          style: form
        - allowEmptyValue: true
          description: |
            Limit caps the returned suggestions. Defaults to 50, capped at 200.
          explode: true
          in: query
          name: limit
          required: false
          schema:
            format: int64
            type: integer
          style: form
        - allowEmptyValue: true
          description: |
            Offset skips that many suggestions, for paging.
          explode: true
          in: query
          name: offset
          required: false
          schema:
            format: int64
            type: integer
          style: form
        - allowEmptyValue: true
          description: >
            AllDecisions returns EVERY decision the organization made, newest
            first, one row per decision rather than one per lead — including
            decisions already carried out, refused, expired or replaced, so one
            lead appears as many times as it was decided about. Omitted, the
            read is each lead's latest decision only, highest priority first,
            which is the queue a person works.
          explode: true
          in: query
          name: all_decisions
          required: false
          schema:
            type: boolean
          style: form
      responses:
        '200':
          content:
            application/json:
              schema:
                properties:
                  limit:
                    format: int64
                    type: integer
                  next_actions:
                    items:
                      $ref: '#/components/schemas/leadaction.NextAction'
                    type: array
                  offset:
                    format: int64
                    type: integer
                type: object
          description: Success response
        default:
          $ref: '#/components/responses/APIError'
components:
  schemas:
    leadaction.NextAction:
      properties:
        accompanying_email:
          allOf:
            - $ref: '#/components/schemas/leadaction.AccompanyingEmailState'
          description: >
            its gated action. Null on every decision that carries none — which
            is every email, wait, close and handoff, and every decision written
            before accompanying emails existed.
          title: >
            AccompanyingEmail is the email this decision sent, or still owes,
            beside
        action_input:
          type: object
        action_kind:
          type: string
        approval_request_id:
          type: string
        canonical_lead_id:
          type: string
        created_by:
          type: string
        dataset_id:
          type: string
        decided_at:
          format: date-time
          type: string
        decided_by:
          type: string
        decided_by_external_ref:
          description: >
            handles for the person who decided this action and the person who
            took that decision back — opaque strings Erdo stores verbatim and
            never interprets.


            They exist because an application built on \`/v1\` authenticates a
            whole team with ONE organization API key, so DecidedBy — the Erdo
            account that key belongs to — is the same person for every decision
            anybody there makes. The caller is the only party that can say which
            of its users acted, so it says, and it resolves these back to names
            on its own side.


            ATTRIBUTION, NEVER AUTHENTICATION. Anything holding the
            organization's key can write any value here; Erdo does not verify
            it, must never branch on it, authorize by it, or resolve it against
            an Erdo identity. It is fine for "Approved by Ana" on a card and
            must never be presented as proof of who acted. Empty means the
            caller offered no name, which is every decision made before this
            existed.
          title: >
            DecidedByExternalRef and UndoneByExternalRef are the CALLING
            PRODUCT's own
          type: string
        due_at:
          format: date-time
          type: string
        error:
          type: string
        evaluated_at:
          format: date-time
          type: string
        executed_at:
          format: date-time
          type: string
        execution_ref:
          type: string
        facts:
          $ref: '#/components/schemas/leadaction.LeadFacts'
        handoff_alert:
          allOf:
            - $ref: '#/components/schemas/leadaction.HandoffAlertState'
          description: >
            handoff is waiting for them. Null on every decision that owes none —
            everything that is not a handoff, every handoff filed while the
            playbook named nobody to tell, and every decision written before
            migration 012.


            It is OPERATOR-ONLY, and the one field on this struct that is.
            Everything else here describes what Erdo did about a LEAD; this
            describes Erdo emailing the development's staff, which is the
            development's own internal business and none of a client's. A
            surface that serves a client audience must neither list it nor offer
            its ref to the email viewer.
          title: |
            HandoffAlert is the email that told the development's own desk this
        id:
          type: string
        lead_reference:
          type: string
        mode:
          type: string
        model:
          type: string
        playbook_revision:
          format: int64
          type: integer
        policy_digest:
          description: >
            is what says whether the decision is stale — not the revision
            number. The revision bumps on every save, so a decision at revision
            9 may have been decided under exactly the rules revision 10 carries;
            comparing it with LeadPlaybook.PolicyDigest answers the question the
            revision only hints at. Empty on every decision written before
            digests existed and on one a person recorded by hand. See policy.go
            for the two halves it is made of.
          title: >
            PolicyDigest identifies the playbook this decision was made under,
            and it
          type: string
        priority:
          type: string
        priority_reason:
          type: string
        rationale:
          type: string
        revisit_at:
          format: date-time
          type: string
        rule:
          type: string
        source:
          type: string
        stage:
          type: string
        status:
          type: string
        undone_by_external_ref:
          type: string
      title: |
        NextAction is a stored suggestion as the API returns it.
      type: object
    leadaction.AccompanyingEmailState:
      description: >
        out beside a gated decision: whether it went, when, in what words, and
        why it did not if it did not.


        It joins the row's own columns (the authoritative state) with the draft
        stored in action\_input, so a caller does not have to read two things
        and work out which one is true.
      properties:
        body_markdown:
          type: string
        error:
          title: |
            Error is why it has not gone, in the words a person reads.
          type: string
        execution_ref:
          title: |
            ExecutionRef is the mailer's id for the email that went.
          type: string
        sent_at:
          format: date-time
          type: string
        status:
          title: >
            Status is pending, sending, sent, failed or skipped. See the
            constants.
          type: string
        subject:
          type: string
        to:
          type: string
      title: >
        AccompanyingEmailState is what a surface needs to render the email that
        went
      type: object
    leadaction.LeadFacts:
      description: |
        means the lead has not told us.
      properties:
        bedrooms:
          $ref: '#/components/schemas/leadaction.LeadFact'
        broker:
          $ref: '#/components/schemas/leadaction.LeadFact'
        budget:
          $ref: '#/components/schemas/leadaction.LeadFact'
        financing:
          $ref: '#/components/schemas/leadaction.LeadFact'
        language:
          $ref: '#/components/schemas/leadaction.LeadFact'
        purpose:
          $ref: '#/components/schemas/leadaction.LeadFact'
        timeline:
          $ref: '#/components/schemas/leadaction.LeadFact'
      title: |
        LeadFacts is what the evaluation understood about the lead. A nil field
      type: object
    leadaction.HandoffAlertState:
      description: >
        desk a handoff is waiting: whether it went, when, the message to open,
        and why it did not go if it did not.


        The alert IS a handoff's delivery. Nothing else happens when a handoff
        is carried out — deliverHandoff records the literal string "accepted"
        and sends nothing — so a surface that wants to say what a handoff DID
        has to read this and not the row's execution ref. It is also why these
        facts are exposed at all: a sent alert is a real, openable message, and
        the timeline used to show a handoff as an unopenable line that mentioned
        no email whatever.


        It reads only the row's own columns, unlike AccompanyingEmailState,
        because the alert's words are not drafted onto the decision — they are
        composed at send time from the card by buildHandoffAlert. The message
        itself is read back from the email service by ExecutionRef, which is the
        only copy of it there is.
      properties:
        error:
          description: |
            a person reads.
          title: >
            Error is why it has not gone, or which recipients it missed, in the
            words
          type: string
        execution_ref:
          description: >
            it. One alert is one message per recipient and this is the first
            copy that sent; every copy carries the same words, so it opens what
            the desk read. Empty on an alert that has not gone, and on one sent
            before the id was recorded (migration 013) — in which case there is
            nothing to open and a surface must not pretend otherwise.
          title: >
            ExecutionRef is the email service's id for the alert, which is what
            opens
          type: string
        sent_at:
          format: date-time
          type: string
        status:
          description: |
            constants in handoff\_alert.go.
          title: |
            Status is pending, sending, sent or failed. See the HandoffAlert*
          type: string
      title: >
        HandoffAlertState is what a surface needs to render the alert that told
        the
      type: object
    leadaction.LeadFact:
      description: |
        read it from, so a person can check the reading against the row.
      properties:
        source_column:
          type: string
        value:
          type: string
      title: >
        LeadFact is one thing the evaluation read about the lead and the column
        it
      type: object
  responses:
    APIError:
      content:
        application/json:
          schema:
            externalDocs:
              url: https://pkg.go.dev/encore.dev/beta/errs#Error
            properties:
              code:
                description: Error code
                example: not_found
                externalDocs:
                  url: https://pkg.go.dev/encore.dev/beta/errs#ErrCode
                type: string
              details:
                description: Error details
                type: object
              message:
                description: Error message
                type: string
            title: APIError
            type: object
      description: Error response
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: An Erdo API key (erdo_api_...) or scoped token (erdo_token_...).

````