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

# Start ownership transfer

> <Info>This API is in beta. Endpoints, fields, and behavior may still change, so avoid depending on it in production.</Info>

Invites a new owner for the app by email, which starts an ownership transfer.

The recipient gets an email with a link, and the transfer completes only once they sign in and accept it. Nothing about the app changes until then. The invitation expires after 7 days. Check first that it can be sent, and what would transfer with the app, with [Check ownership transfer](/api-reference/check-ownership-transfer). Afterwards, follow it with [Get pending ownership transfer](/api-reference/get-pending-ownership-transfer), [Resend ownership transfer](/api-reference/resend-ownership-transfer), or [Cancel ownership transfer](/api-reference/cancel-ownership-transfer).

When the recipient accepts, they pick the workspace that receives the app. If it's a different workspace, the app's current collaborators lose access and its AI chat history is cleared. Integrations and secrets follow the choices in the request. To pass the app to a member of its workspace right away, with no invitation, use [Transfer ownership to a workspace member](/api-reference/transfer-ownership-to-a-workspace-member).

An app can have only one pending transfer. Starting another while one is pending is rejected, whoever it's for. An expired invitation is replaced.

You need to own the app or be an owner or admin of its workspace. A workspace admin who doesn't own the app also needs an Enterprise workspace or approved partner status. An invitation to someone outside the workspace needs that status too, and only workspace owners and admins can send one. The workspace's transfer policy can narrow that to owners, or turn it off.

This is limited to 30 requests a minute per workspace. Some workspaces have a different limit. Invitation emails are also limited to 5 an hour and 20 a day per caller, and to 3 an hour and 10 a day per recipient. Resending counts toward the same limits.

<Note>This endpoint accepts a personal API key. A read-only key is refused, and workspace API keys are not accepted.</Note>



## OpenAPI

````yaml /developers/references/app-management/app-management-openapi.json post /api/apps/{app_id}/ownership/transfer
openapi: 3.1.0
info:
  title: Base44 App Management API
  version: 1.0.0
servers:
  - url: https://app.base44.com
security:
  - PersonalAccessTokenAuth: []
paths:
  /api/apps/{app_id}/ownership/transfer:
    post:
      summary: Start ownership transfer
      description: >-
        <Info>This API is in beta. Endpoints, fields, and behavior may still
        change, so avoid depending on it in production.</Info>


        Invites a new owner for the app by email, which starts an ownership
        transfer.


        The recipient gets an email with a link, and the transfer completes only
        once they sign in and accept it. Nothing about the app changes until
        then. The invitation expires after 7 days. Check first that it can be
        sent, and what would transfer with the app, with [Check ownership
        transfer](/api-reference/check-ownership-transfer). Afterwards, follow
        it with [Get pending ownership
        transfer](/api-reference/get-pending-ownership-transfer), [Resend
        ownership transfer](/api-reference/resend-ownership-transfer), or
        [Cancel ownership transfer](/api-reference/cancel-ownership-transfer).


        When the recipient accepts, they pick the workspace that receives the
        app. If it's a different workspace, the app's current collaborators lose
        access and its AI chat history is cleared. Integrations and secrets
        follow the choices in the request. To pass the app to a member of its
        workspace right away, with no invitation, use [Transfer ownership to a
        workspace
        member](/api-reference/transfer-ownership-to-a-workspace-member).


        An app can have only one pending transfer. Starting another while one is
        pending is rejected, whoever it's for. An expired invitation is
        replaced.


        You need to own the app or be an owner or admin of its workspace. A
        workspace admin who doesn't own the app also needs an Enterprise
        workspace or approved partner status. An invitation to someone outside
        the workspace needs that status too, and only workspace owners and
        admins can send one. The workspace's transfer policy can narrow that to
        owners, or turn it off.


        This is limited to 30 requests a minute per workspace. Some workspaces
        have a different limit. Invitation emails are also limited to 5 an hour
        and 20 a day per caller, and to 3 an hour and 10 a day per recipient.
        Resending counts toward the same limits.


        <Note>This endpoint accepts a personal API key. A read-only key is
        refused, and workspace API keys are not accepted.</Note>
      operationId: initiate_transfer_api_apps__app_id__ownership_transfer_post
      parameters:
        - name: app_id
          in: path
          required: true
          schema:
            type: string
            description: ID of the app.
            title: App Id
          description: ID of the app.
          example: 6820f3a4e7b91d003c45a1f2
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InitiateTransferRequest'
      responses:
        '200':
          description: The new transfer, waiting for the recipient to accept it.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PendingOwnershipTransfer'
        '400':
          description: >-
            The new owner is you or the app's current owner, their account is
            disabled, the app already has a pending transfer or is blocked, a
            `same_workspace` recipient isn't an owner, admin, editor, or member
            of the workspace, or `integration_decisions` or `secret_decisions`
            is empty while the app has integrations or secrets, names one the
            app doesn't have, or transfers a secret that has no value.
        '401':
          description: Missing or invalid credentials.
        '403':
          description: >-
            You can't manage ownership transfers for this app, the workspace's
            transfer policy doesn't let you invite someone outside it, the app
            came from the marketplace, your API key is read-only, you used a
            workspace API key, or the app's workspace isn't Enterprise and you
            aren't an approved partner, for an invitation outside the workspace.
        '404':
          description: >-
            The app doesn't exist, or it's outside the workspace or apps your
            API key is scoped to.
        '409':
          description: The app is moving to another workspace.
        '422':
          description: >-
            `new_owner_email` is missing or isn't a valid email address, or
            another field has an invalid value.
        '429':
          description: Rate limit or invitation email limit reached. Retry later.
components:
  schemas:
    InitiateTransferRequest:
      properties:
        new_owner_email:
          type: string
          format: email
          title: New Owner Email
          description: >-
            Email address of the new owner. The invitation goes there, and they
            need a Base44 account with this email to accept it.
          example: jane@acme.com
        destination:
          anyOf:
            - type: string
              enum:
                - same_workspace
                - external_email
            - type: 'null'
          title: Destination
          description: >-
            Either `same_workspace`, to invite an owner, admin, editor, or
            member of the app's workspace, or `external_email`, to invite
            anyone. Defaults to `external_email`.
          example: external_email
        disconnect_integrations:
          type: boolean
          title: Disconnect Integrations
          description: >-
            Whether to disconnect all of the app's integrations when the
            recipient accepts into another workspace (`true`) or keep them
            connected (`false`). It's used only when you send neither
            `integration_decisions` nor `secret_decisions`, and has no effect
            when the recipient accepts into the app's current workspace. To
            disconnect integrations in that case, send `integration_decisions`.
            Defaults to `true`.
          default: true
          example: true
        integration_decisions:
          anyOf:
            - items:
                $ref: '#/components/schemas/IntegrationTransferDecisionRequest'
              type: array
            - type: 'null'
          title: Integration Decisions
          description: >-
            What happens to each of the app's integrations when the recipient
            accepts. An integration you leave out is disconnected, and so is one
            whose `can_keep_connected` is `false`, whatever you choose. If you
            send `secret_decisions` without this, it counts as empty, which is
            rejected when the app has integrations.
          example:
            - action: keep_connected
              integration_type: slack
        secret_decisions:
          anyOf:
            - items:
                $ref: '#/components/schemas/SecretTransferDecisionRequest'
              type: array
            - type: 'null'
          title: Secret Decisions
          description: >-
            What happens to each of the app's secrets when the recipient
            accepts. A secret you leave out needs a new value. Values never go
            in the request, and are copied on the server. If you send
            `integration_decisions` without this, it counts as empty, which is
            rejected when the app has secrets. When you send neither list, every
            secret keeps its value.
          example:
            - action: require_new_value
              secret_name: STRIPE_API_KEY
        keep_sender_as_collaborator:
          type: boolean
          title: Keep Sender As Collaborator
          description: >-
            Whether the app's current owner keeps editor access to the app after
            the transfer (`true`) or loses their direct access to it (`false`).
            An owner or admin of the workspace the app ends up in keeps access
            through that workspace either way. Defaults to `false`.
          default: false
          example: false
      type: object
      required:
        - new_owner_email
      title: InitiateTransferRequest
      description: The ownership transfer invitation to send.
    PendingOwnershipTransfer:
      properties:
        id:
          type: string
          title: Id
          description: ID of the ownership transfer.
          example: 68d4b1e9c2a7f3001e5b8c40
        app_id:
          type: string
          title: App Id
          description: ID of the app being transferred.
          example: 6820f3a4e7b91d003c45a1f2
        new_owner_email:
          type: string
          title: New Owner Email
          description: Email address the transfer invitation was sent to.
          example: jane@acme.com
        status:
          type: string
          title: Status
          description: >-
            Either `pending`, while the invitation waits for the recipient, or
            `accepting`, while the recipient's acceptance is being applied.
          example: pending
        expires_at:
          type: string
          title: Expires At
          description: >-
            When the invitation expires, as a UTC timestamp in ISO 8601 format.
            The recipient can't accept it after that.
          example: '2026-10-05T09:23:41.512000Z'
      type: object
      required:
        - id
        - app_id
        - new_owner_email
        - status
        - expires_at
      title: PendingOwnershipTransfer
      description: An ownership transfer waiting for its recipient to accept it.
    IntegrationTransferDecisionRequest:
      properties:
        integration_type:
          type: string
          minLength: 1
          title: Integration Type
          description: >-
            Integration type, from `transfer_package.integrations` in the
            preflight result.
          example: slack
        action:
          type: string
          enum:
            - keep_connected
            - disconnect
          title: Action
          description: >-
            Either `keep_connected`, to leave the integration connected for the
            new owner, or `disconnect`.
          example: keep_connected
      type: object
      required:
        - integration_type
        - action
      title: IntegrationTransferDecisionRequest
      description: Sender decision for one app integration.
    SecretTransferDecisionRequest:
      properties:
        secret_name:
          type: string
          minLength: 1
          title: Secret Name
          description: >-
            Name of the secret, from `transfer_package.secrets` in the preflight
            result.
          example: STRIPE_API_KEY
        action:
          type: string
          enum:
            - transfer_value
            - require_new_value
          title: Action
          description: >-
            Either `transfer_value`, to copy the secret's value to the new
            owner, or `require_new_value`, to clear it so the new owner sets
            their own.
          example: require_new_value
      type: object
      required:
        - secret_name
        - action
      title: SecretTransferDecisionRequest
      description: Sender decision for one app secret. Values are never sent by the client.
  securitySchemes:
    PersonalAccessTokenAuth:
      type: http
      scheme: bearer
      description: 'Personal access token, sent as `Authorization: Bearer <token>`.'

````