> ## 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.

# Upload enhanced Google Ads conversions

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

Adds hashed buyer details to conversions you have already reported, so Google can match more of them to a click.

Use it when you learn who the buyer was after the conversion was reported, for example a form submitted after checkout. Each adjustment finds its conversion by the `order_id` you sent originally, so it only works for a conversion you reported with one. It changes the details on an existing conversion and never creates a new one, so [Upload conversions](/api-reference/upload-google-ads-conversions) has to run first.

Hash each value yourself with SHA-256 over the lowercased, trimmed input and send lowercase hex. Base44 forwards what you send without hashing or normalizing it, so an unhashed or differently formatted value simply fails to match and reports as accepted.

Read the outcome from `total_uploaded` rather than `status`, which reports `success` as soon as one adjustment lands.

<Note>There is no cap on how many rows you can send and no rate limit on this endpoint. Base44 sends them to Google in batches of 2,000, one batch after another, while your request stays open, so a very large list means a very long request. Keep each call to a few thousand rows and send several calls instead.</Note>

<Warning>A 409 means the request to Google timed out after it was sent, so the adjustments may or may not have landed. Unlike [Upload conversions](/api-reference/upload-google-ads-conversions), this endpoint keeps no record of what it has sent, so a retry can apply the same adjustment twice. Check the conversion in Google Ads before retrying.</Warning>

<Note>This endpoint accepts a personal API key. Workspace API keys are not authorized for it and are rejected with a 403.</Note>



## OpenAPI

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


        Adds hashed buyer details to conversions you have already reported, so
        Google can match more of them to a click.


        Use it when you learn who the buyer was after the conversion was
        reported, for example a form submitted after checkout. Each adjustment
        finds its conversion by the `order_id` you sent originally, so it only
        works for a conversion you reported with one. It changes the details on
        an existing conversion and never creates a new one, so [Upload
        conversions](/api-reference/upload-google-ads-conversions) has to run
        first.


        Hash each value yourself with SHA-256 over the lowercased, trimmed input
        and send lowercase hex. Base44 forwards what you send without hashing or
        normalizing it, so an unhashed or differently formatted value simply
        fails to match and reports as accepted.


        Read the outcome from `total_uploaded` rather than `status`, which
        reports `success` as soon as one adjustment lands.


        <Note>There is no cap on how many rows you can send and no rate limit on
        this endpoint. Base44 sends them to Google in batches of 2,000, one
        batch after another, while your request stays open, so a very large list
        means a very long request. Keep each call to a few thousand rows and
        send several calls instead.</Note>


        <Warning>A 409 means the request to Google timed out after it was sent,
        so the adjustments may or may not have landed. Unlike [Upload
        conversions](/api-reference/upload-google-ads-conversions), this
        endpoint keeps no record of what it has sent, so a retry can apply the
        same adjustment twice. Check the conversion in Google Ads before
        retrying.</Warning>


        <Note>This endpoint accepts a personal API key. Workspace API keys are
        not authorized for it and are rejected with a 403.</Note>
      operationId: >-
        upload_enhanced_conversion_api_apps__app_id__google_ads_conversions_upload_enhanced_post
      parameters:
        - name: app_id
          in: path
          required: true
          schema:
            type: string
            description: >-
              ID of the app whose Google Ads conversion tracking you want to
              manage.
            title: App Id
          description: >-
            ID of the app whose Google Ads conversion tracking you want to
            manage.
          example: 6820f3a4e7b91d003c45a1f2
      requestBody:
        required: true
        content:
          application/json:
            schema:
              title: UploadEnhancedConversions
              type: object
              properties:
                adjustments:
                  type: array
                  description: >-
                    The adjustments to apply. An empty list is accepted and
                    changes nothing.
                  items:
                    type: object
                    required:
                      - conversion_action_id
                      - order_id
                      - adjustment_date_time
                      - user_identifiers
                    properties:
                      conversion_action_id:
                        type: string
                        description: >-
                          Google Ads' own ID for the goal the original
                          conversion counted towards, as returned in
                          `google_action_id` by [List conversion
                          actions](/api-reference/list-google-ads-conversion-actions).
                        example: '7654321'
                      order_id:
                        type: string
                        description: >-
                          The `order_id` you sent on the original conversion. It
                          is how Google finds the conversion to enhance, so an
                          adjustment without it cannot be matched.
                        example: ORD-10482
                      adjustment_date_time:
                        type: string
                        description: >-
                          When you are making the adjustment, as `YYYY-MM-DD
                          HH:MM:SS+HH:MM` including the offset. Google rejects
                          any other format with a 400.
                        example: '2026-08-26 09:15:00+00:00'
                      user_identifiers:
                        type: object
                        description: >-
                          Hashed details of the buyer to add to the conversion.
                          Hash every value yourself, because Base44 sends them
                          as given. An adjustment that ends up with no usable
                          identifier is dropped before Google sees it.
                        properties:
                          hashed_email:
                            type: string
                            description: >-
                              The buyer's email address, lowercased, trimmed,
                              and SHA-256 hashed to lowercase hex.
                            example: >-
                              d5b8e2b9a1c4f60e7a2f3c8d91b45e6f70a1c2d3e4f5061728394a5b6c7d8e9f
                          hashed_phone_number:
                            type: string
                            description: >-
                              The buyer's phone number in E.164 form, SHA-256
                              hashed to lowercase hex.
                            example: >-
                              9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a0
                          hashed_first_name:
                            type: string
                            description: >-
                              The buyer's first name, lowercased and SHA-256
                              hashed to lowercase hex. Base44 only sends it
                              together with `hashed_last_name`, so one without
                              the other is dropped and has no effect.
                            example: >-
                              3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d
                          hashed_last_name:
                            type: string
                            description: >-
                              The buyer's last name, lowercased and SHA-256
                              hashed to lowercase hex. Send it together with
                              `hashed_first_name`, because one without the other
                              is dropped.
                            example: >-
                              706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a392817
                      user_agent:
                        type: string
                        description: >-
                          The browser user agent from the original conversion,
                          which helps Google match it. Leave it out when you do
                          not have it.
                        example: >-
                          Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)
                          AppleWebKit/537.36
                  example:
                    - conversion_action_id: '7654321'
                      order_id: ORD-10482
                      adjustment_date_time: '2026-08-26 09:15:00+00:00'
                      user_identifiers:
                        hashed_email: >-
                          d5b8e2b9a1c4f60e7a2f3c8d91b45e6f70a1c2d3e4f5061728394a5b6c7d8e9f
            example:
              adjustments:
                - conversion_action_id: '7654321'
                  order_id: ORD-10482
                  adjustment_date_time: '2026-08-26 09:15:00+00:00'
                  user_identifiers:
                    hashed_email: >-
                      d5b8e2b9a1c4f60e7a2f3c8d91b45e6f70a1c2d3e4f5061728394a5b6c7d8e9f
      responses:
        '200':
          description: What happened to the batch of adjustments.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EnhancedConversionUploadResult'
        '400':
          description: >-
            Google Ads rejected the whole request, for example a malformed
            `conversion_date_time` or a `conversion_action_id` that is not on
            the account. The response message carries Google's reason.
        '401':
          description: Missing or invalid credentials.
        '403':
          description: >-
            You don't have access to this app, the app does not exist, or you
            used a workspace API key. A missing app and an app you cannot reach
            are deliberately the same answer.
        '404':
          description: The app has no connected Google Ads account.
        '409':
          description: >-
            The request to Google Ads timed out after being sent, so the
            adjustments may or may not have landed. Check the conversion in
            Google Ads before retrying, because a retry can apply the same
            adjustment twice.
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          description: Google Ads is rate limiting the account. Retry later.
components:
  schemas:
    EnhancedConversionUploadResult:
      properties:
        status:
          type: string
          title: Status
          description: >-
            Whether anything reached Google. The value is `success` when at
            least one adjustment landed and `no_rows_uploaded` when none did, so
            it does not tell you the whole batch landed.
          example: success
        total_submitted:
          type: integer
          title: Total Submitted
          description: How many adjustments you sent.
          example: 5
        total_uploaded:
          type: integer
          title: Total Uploaded
          description: >-
            How many adjustments Google accepted. Anything short of
            `total_submitted` is made up of adjustments dropped for carrying no
            usable hashed identifier and adjustments Google rejected one by one,
            and the response does not separate the two.
          example: 4
      type: object
      required:
        - status
        - total_submitted
        - total_uploaded
      title: EnhancedConversionUploadResult
      description: What happened to a batch of enhanced-conversion adjustments.
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: api_key
      description: Personal API key.

````