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

# Reassign a booked call to a different closer

> 
Swap the host on a booked call.

For an **upcoming** call, under the hood this cancels the existing calendar
event and creates a fresh one under the new closer's calendar, then fires the
`call.closer_reassigned` webhook.

For a call that **already happened**, the swap is **attribution-only**: the
closer columns on the call row are rewritten (so deals, analytics, and
commission reads credit the right closer), but no calendar event is created
or deleted — the historical event stays on the host who actually held the
call. The response and the webhook payload carry `attribution_only: true`,
and the target closer does **not** need a connected calendar grant.

**Who can reassign:** changing a call's host is admin only on every surface.
An API key keeps access. A signed-in member (a Clerk session) who is not an
organization admin gets `403` `AUTHORIZATION_ERROR` and nothing changes.
This applies to a call that already happened, too.

**Constraints:**
- Call must be in `booking` kind (intent calls cannot be reassigned)
- Call must not be cancelled: a cancelled call gets `409`
  `CALL_CANCELLED` and nothing changes. Create a new call instead
- A **declined** call can be reassigned while its time is still to come: it
  goes back to waiting for the guest's answer, and the new closer's
  invitation asks the guest again. Once a declined call's time has passed it
  cannot be reassigned: it gets `400` `VALIDATION_ERROR` and nothing changes
- New closer must be a member of the organization; for **upcoming** calls
  they must also have a connected calendar grant
- Cross-org reassignment is blocked

**Side effects visible to Partner API consumers (upcoming calls):**
- DB row's `closer_id` / `closer_email` / `closer_name` / `nylas_event_id`
  / `nylas_grant_id` / `conferencing_link` are updated atomically
- New conferencing link is issued (old one is invalidated)
- The calendar provider sends the replacement invitation with the guest's
  native RSVP controls. Aura also requests withdrawal of the old invitation;
  if that best-effort delete fails, `old_event_orphaned=true` reports it
- `call.closer_reassigned` webhook fires to all subscribers
- The recording bot moves to the new meeting link about 20 seconds after the
  response, or before it for a call that starts within 2 minutes. Until then `updated_call.notetaker_id`,
  `notetaker_state` and `meeting_link_sent` can still describe the bot
  that was on the old event

**Side effects (past calls, attribution-only):**
- Only `closer_id` / `closer_email` / `closer_name` change; the event id,
  conferencing link, recording, outcome, and setter attribution stay put
- `call.closer_reassigned` webhook fires with `attribution_only: true`

**Sent by Aura for upcoming calls, about 20 seconds after the response:**
- One branded email telling the guest their host has changed (and the new
  time, when it moved). It carries no calendar file: the replacement
  invitation above is the calendar update. Partners should not send their own
- The Zapier event and the `call.closer_reassigned` Partner webhook, from the
  same shared reassignment service the dashboard uses
  

Swap the host on a booked call.

For an **upcoming** call, under the hood this cancels the existing calendar
event and creates a fresh one under the new closer's calendar, then fires the
`call.closer_reassigned` webhook.

For a call that **already happened**, the swap is **attribution-only**: the
closer columns on the call row are rewritten (so deals, analytics, and
commission reads credit the right closer), but no calendar event is created
or deleted — the historical event stays on the host who actually held the
call. The response and the webhook payload carry `attribution_only: true`,
and the target closer does **not** need a connected calendar grant.

**Who can reassign:** changing a call's host is admin only on every surface.
An API key keeps access. A signed-in member (a Clerk session) who is not an
organization admin gets `403` `AUTHORIZATION_ERROR` and nothing changes.
This applies to a call that already happened, too.

**Constraints:**

* Call must be in `booking` kind (intent calls cannot be reassigned)
* Call must not be cancelled: a cancelled call gets `409`
  `CALL_CANCELLED` and nothing changes. Create a new call instead
* A **declined** call can be reassigned while its time is still to come: it
  goes back to waiting for the guest's answer, and the new closer's
  invitation asks the guest again. Once a declined call's time has passed it
  cannot be reassigned: it gets `400` `VALIDATION_ERROR` and nothing changes
* New closer must be a member of the organization; for **upcoming** calls
  they must also have a connected calendar grant
* Cross-org reassignment is blocked

**Side effects visible to Partner API consumers (upcoming calls):**

* DB row's `closer_id` / `closer_email` / `closer_name` / `nylas_event_id`
  / `nylas_grant_id` / `conferencing_link` are updated atomically
* New conferencing link is issued (old one is invalidated)
* The calendar provider sends the replacement invitation with the guest's
  native RSVP controls. Aura also requests withdrawal of the old invitation;
  if that best-effort delete fails, `old_event_orphaned=true` reports it
* `call.closer_reassigned` webhook fires to all subscribers
* The recording bot moves to the new meeting link about 20 seconds after the
  response, or before it for a call that starts within 2 minutes. Until then `updated_call.notetaker_id`,
  `notetaker_state` and `meeting_link_sent` can still describe the bot
  that was on the old event

**Side effects (past calls, attribution-only):**

* Only `closer_id` / `closer_email` / `closer_name` change; the event id,
  conferencing link, recording, outcome, and setter attribution stay put
* `call.closer_reassigned` webhook fires with `attribution_only: true`

**Sent by Aura for upcoming calls, about 20 seconds after the response:**

* One branded email telling the guest their host has changed (and the new
  time, when it moved). It carries no calendar file: the replacement
  invitation above is the calendar update. Partners should not send their own
* The Zapier event and the `call.closer_reassigned` Partner webhook, from the
  same shared reassignment service the dashboard uses


## OpenAPI

````yaml openapi.json POST /v1/calls/{id}/reassign-closer
openapi: 3.1.0
info:
  contact:
    email: support@aura-app.ai
    name: Aura Support
  description: >-
    # Aura Partner Integrations API


    > **Alpha Release** - This API is under active development. Endpoints,
    request/response schemas, and behaviors may change without prior notice. We
    recommend pinning to specific response fields you need and handling unknown
    fields gracefully.


    Enterprise REST API for external partner integrations including

    commission platforms, external mobile apps, and client booking widgets.


    ## MCP Connector


    Aura also exposes a **Model Context Protocol** server at `/mcp` so AI

    assistants (Claude, ChatGPT) can answer questions about a user's own sales
    data.

    If you are building an assistant integration rather than a server-to-server
    one,

    that is almost certainly the surface you want — it is task-shaped ("prep me
    for

    my next call") rather than resource-shaped, and it handles auth per-user.


    Read-only. OAuth 2.1 + PKCE, with Clerk as the authorization server;
    discover it

    from `/.well-known/oauth-protected-resource`. Setup guide:

    https://docs.api.aura-app.ai/mcp-connector


    ## Authentication


    Authenticated endpoints support two authentication methods:


    **1. API Key (for partners and integrations):**

    ```

    Authorization: Bearer aura_pk_live_xxxxxxxxxxxxxxxx

    ```

    Get your API key from the Aura dashboard at Settings > API Keys.


    **2. Clerk JWT (for mobile and web apps):**

    ```

    Authorization: Bearer <clerk_jwt_token>

    ```

    Use Clerk's authentication SDK to obtain a JWT token with org claims.


    ## Rate Limiting


    - **Per API Key:** 100 requests/minute

    - **Per Organization:** 1000 requests/minute


    Rate limit headers are included in all responses:

    - `X-RateLimit-Limit`: Maximum requests allowed

    - `X-RateLimit-Remaining`: Remaining requests in current window

    - `X-RateLimit-Reset`: Unix timestamp when limit resets


    These counters are held per serving instance, so under concurrency the

    effective ceiling is higher than the number above and the headers describe
    one

    instance's view rather than a global total. Treat a 429 as backpressure to
    obey

    and pace your client to the documented rate — but do not rely on us to
    reject

    your 101st request, and do not derive a global remaining-quota figure from
    the

    headers. The limit may become globally enforced without notice, so a client

    that stays within it will not be affected when that happens.


    ## Pagination


    List endpoints support cursor-based pagination:

    - `limit`: Number of results per page (default: 50, max: 100)

    - `cursor`: Opaque cursor for next page


    ## Error Handling


    All errors follow a standard format:


    ```json

    {
      "success": false,
      "error": "Error message",
      "code": "ERROR_CODE"
    }

    ```


    Common HTTP status codes:

    - **400** Bad Request - Invalid input (`VALIDATION_ERROR`)

    - **401** Unauthorized - Missing or invalid API key (`AUTHENTICATION_ERROR`)

    - **402** Payment Required - The key is valid, but the organization's
    subscription is not active (`PAYMENT_REQUIRED`). Every authenticated
    endpoint can return this. Retrying will not help until the account's payment
    method is updated in Aura; surface it to the account owner rather than
    treating it as an auth failure.

    - **403** Forbidden - Insufficient permissions (`AUTHORIZATION_ERROR`)

    - **404** Not Found - Resource not found (`NOT_FOUND`)

    - **409** Conflict - Resource state prevents the operation (`CONFLICT`)

    - **413** Payload Too Large - Request body exceeds 256KB
    (`PAYLOAD_TOO_LARGE`)

    - **429** Too Many Requests - Rate limit exceeded (`RATE_LIMIT_EXCEEDED`)

    - **500** Internal Server Error - Server error (`INTERNAL_ERROR`)


    ## Webhooks


    Subscribe to real-time events using the Webhooks API. All webhook payloads

    are signed with HMAC-SHA256 for security verification.


    Delivery is at-least-once. Every payload carries an `idempotency_key` that

    is stable across retries of the same event, so you can enforce exactly-once

    with a `(subscription_id, idempotency_key)` unique constraint on your side.


    For full documentation, visit
    [docs.aura-app.ai/api](https://docs.aura-app.ai/api)
  license:
    name: Proprietary
  title: Aura Partner Integrations API
  version: 1.0.0-alpha
servers:
  - description: Production
    url: https://api.aura-app.ai
  - description: Staging
    url: https://staging-api.aura-app.ai
  - description: Local Development
    url: http://localhost:3001
security:
  - bearerAuth: []
tags:
  - description: Lead management operations
    name: Leads
  - description: Call booking and management
    name: Calls
  - description: Booking link configuration (read-only)
    name: Booking Links
  - description: Product catalog (read-only)
    name: Products
  - description: Payment tracking (read-only)
    name: Payments
  - description: Public booking creation
    name: Bookings
  - description: Real-time event subscriptions and webhook management
    name: Webhooks
  - description: >-
      Team member information for commission attribution. **Alpha** - schema may
      change without notice.
    name: Team (Alpha)
  - description: >-
      Dashboard analytics, lead source attribution, and objection analysis.
      **Alpha** - schema may change without notice.
    name: Analytics (Alpha)
  - description: System endpoints (health checks)
    name: System
paths:
  /v1/calls/{id}/reassign-closer:
    post:
      tags:
        - Calls
      summary: Reassign a booked call to a different closer
      description: >-

        Swap the host on a booked call.


        For an **upcoming** call, under the hood this cancels the existing
        calendar

        event and creates a fresh one under the new closer's calendar, then
        fires the

        `call.closer_reassigned` webhook.


        For a call that **already happened**, the swap is **attribution-only**:
        the

        closer columns on the call row are rewritten (so deals, analytics, and

        commission reads credit the right closer), but no calendar event is
        created

        or deleted — the historical event stays on the host who actually held
        the

        call. The response and the webhook payload carry `attribution_only:
        true`,

        and the target closer does **not** need a connected calendar grant.


        **Who can reassign:** changing a call's host is admin only on every
        surface.

        An API key keeps access. A signed-in member (a Clerk session) who is not
        an

        organization admin gets `403` `AUTHORIZATION_ERROR` and nothing changes.

        This applies to a call that already happened, too.


        **Constraints:**

        - Call must be in `booking` kind (intent calls cannot be reassigned)

        - Call must not be cancelled: a cancelled call gets `409`
          `CALL_CANCELLED` and nothing changes. Create a new call instead
        - A **declined** call can be reassigned while its time is still to come:
        it
          goes back to waiting for the guest's answer, and the new closer's
          invitation asks the guest again. Once a declined call's time has passed it
          cannot be reassigned: it gets `400` `VALIDATION_ERROR` and nothing changes
        - New closer must be a member of the organization; for **upcoming**
        calls
          they must also have a connected calendar grant
        - Cross-org reassignment is blocked


        **Side effects visible to Partner API consumers (upcoming calls):**

        - DB row's `closer_id` / `closer_email` / `closer_name` /
        `nylas_event_id`
          / `nylas_grant_id` / `conferencing_link` are updated atomically
        - New conferencing link is issued (old one is invalidated)

        - The calendar provider sends the replacement invitation with the
        guest's
          native RSVP controls. Aura also requests withdrawal of the old invitation;
          if that best-effort delete fails, `old_event_orphaned=true` reports it
        - `call.closer_reassigned` webhook fires to all subscribers

        - The recording bot moves to the new meeting link about 20 seconds after
        the
          response, or before it for a call that starts within 2 minutes. Until then `updated_call.notetaker_id`,
          `notetaker_state` and `meeting_link_sent` can still describe the bot
          that was on the old event

        **Side effects (past calls, attribution-only):**

        - Only `closer_id` / `closer_email` / `closer_name` change; the event
        id,
          conferencing link, recording, outcome, and setter attribution stay put
        - `call.closer_reassigned` webhook fires with `attribution_only: true`


        **Sent by Aura for upcoming calls, about 20 seconds after the
        response:**

        - One branded email telling the guest their host has changed (and the
        new
          time, when it moved). It carries no calendar file: the replacement
          invitation above is the calendar update. Partners should not send their own
        - The Zapier event and the `call.closer_reassigned` Partner webhook,
        from the
          same shared reassignment service the dashboard uses
          
      parameters:
        - description: Call ID (UUID)
          in: path
          name: id
          required: true
          schema:
            description: Call ID (UUID)
            example: 550e8400-e29b-41d4-a716-446655440000
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReassignCloserBody'
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReassignCloserResponse'
          description: Call successfully reassigned
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: >-
            Validation failed (VALIDATION_ERROR): the call already has that
            closer, the new closer is not a member or has no connected calendar
            (upcoming calls), or the call was declined and its time has passed
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Invalid or missing API key
        '402':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MiddlewareErrorResponse'
          description: The organization's subscription is not active
          headers:
            X-Request-Id:
              description: Request identifier for support
              schema:
                type: string
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: >-
            A signed-in member who is not an organization admin
            (AUTHORIZATION_ERROR). Changing a call's host is admin only; an API
            key keeps access
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Call or target user not found
        '408':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MiddlewareErrorResponse'
          description: >-
            The request exceeded its processing time limit. Check the outcome
            before retrying a write
          headers:
            X-Request-Id:
              description: Request identifier for support
              schema:
                type: string
        '409':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: >-
            The call was cancelled (CALL_CANCELLED), or the new closer's
            calendar is busy at the call's time (CONFLICT)
        '413':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MiddlewareErrorResponse'
          description: The request body exceeds 256KB
          headers:
            X-Request-Id:
              description: Request identifier for support
              schema:
                type: string
        '429':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MiddlewareErrorResponse'
          description: Rate limit exceeded. Wait before retrying
          headers:
            Retry-After:
              description: Seconds to wait before retrying
              schema:
                type: string
            X-RateLimit-Limit:
              description: Requests allowed in the current window
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the current window
              schema:
                type: string
            X-RateLimit-Reset:
              description: Window reset as a Unix timestamp
              schema:
                type: string
            X-Request-Id:
              description: Request identifier for support
              schema:
                type: string
        '500':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MiddlewareErrorResponse'
          description: >-
            Unexpected server failure. Include the request identifier when
            contacting support
          headers:
            X-Request-Id:
              description: Request identifier for support
              schema:
                type: string
        '502':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: >-
            Calendar mutation could not be confirmed. The event may exist;
            retain the attempt reference and do not blindly retry.
      security:
        - bearerAuth: []
components:
  schemas:
    ReassignCloserBody:
      properties:
        new_closer_id:
          description: >-
            Clerk user ID of the closer to reassign the call to (e.g.
            user_2abc123xyz)
          example: user_2abc123xyz
          pattern: ^user_[A-Za-z0-9]+$
          type: string
        override_conflict:
          description: >-
            Deprecated compatibility field. Calendar busy blocks and
            unverifiable availability always prevent a calendar-changing
            reassignment, regardless of this value. Past attribution-only
            reassignment does not change calendars.
          example: false
          type: boolean
      required:
        - new_closer_id
      type: object
    ReassignCloserResponse:
      properties:
        data:
          properties:
            attempt_id:
              format: uuid
              type: string
            attribution_only:
              description: >-
                True when the call had already happened and only the closer
                credit moved (AUR-2029) — no calendar event was created or
                deleted, and the target closer needed no calendar grant.
              example: false
              type: boolean
            call_id:
              example: call_abc_123
              type: string
            conferencing_link:
              description: >-
                New conferencing URL (old link is invalidated). Unchanged for
                attribution-only reassignments.
              nullable: true
              type: string
            new_closer_id:
              description: User ID of the new closer
              type: string
            new_closer_name:
              description: Display name of the new closer
              type: string
            new_event_id:
              description: >-
                Nylas event ID of the new calendar event. For attribution-only
                reassignments this echoes the call's existing historical event
                id, or "" when it never had one.
              type: string
            old_event_orphaned:
              description: >-
                True if the old Nylas event delete failed — async reconciliation
                will clean it up. Always false for attribution-only
                reassignments.
              example: false
              type: boolean
            previous_closer_id:
              description: User ID of the old closer (null if the call had none)
              nullable: true
              type: string
            previous_closer_name:
              description: Display name of the old closer
              type: string
            source_cleanup_pending:
              type: boolean
          required:
            - call_id
            - previous_closer_id
            - previous_closer_name
            - new_closer_id
            - new_closer_name
            - conferencing_link
            - new_event_id
            - old_event_orphaned
            - attribution_only
          type: object
        success:
          enum:
            - true
          type: boolean
      required:
        - success
        - data
      type: object
    ErrorResponse:
      properties:
        code:
          description: Error code for programmatic handling
          example: NOT_FOUND
          type: string
        error:
          description: Human-readable error message
          example: Lead not found
          type: string
        requestId:
          description: Request ID for support debugging
          example: req_abc123
          type: string
        success:
          enum:
            - false
          type: boolean
      required:
        - success
        - error
        - code
      type: object
    MiddlewareErrorResponse:
      properties:
        code:
          type: string
        error:
          type: string
        requestId:
          type: string
        success:
          enum:
            - false
          type: boolean
      required:
        - success
        - error
        - code
      type: object

````

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