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

# Create and update a review from a custom partner

> This endpoint lets you push into Partoo the reviews you collect on your own platform,
through a **custom review partner** enabled on your organization.

A review is identified by the pair (`partner_slug`, `external_id`):
- the first call with a given pair **creates** the review,
- every later call with the same pair **updates** it in place.

Sending the same payload twice is therefore safe: the second call is a no-op and still
answers `200`. Pushing a review you previously deleted **restores** it.

You can push for partners that are flagged as `is_custom` by
[List review partners](/api-reference/reviews/list-review-partners). Reviews created this
way behave like any other review: they are returned by
[Search for reviews](/api-reference/reviews/search-for-reviews), they can be replied to,
and they trigger the `review_created` / `review_updated` webhooks.

You must use an API key with `ORG_ADMIN` rights and the `review_edit` permission, and the
business must belong to the organization of the API key's.




## OpenAPI

````yaml /assets/openapi/openapi-bundled.yaml post /reviews
openapi: 3.1.0
info:
  title: Partoo Rest API
  version: v2
  license:
    name: © Copyright Partoo
    url: https://www.partoo.co/en/gtu-api/
  x-logo:
    url: >-
      https://partoo-client-images.s3.amazonaws.com/logo-partoo-restapi-white.png
  description: >
    ## Introduction

    The Partoo Rest API allows you to automate all the actions that are possible
    to do in the Partoo Web Application.


    The Partoo Rest API can be used for many different purposes:
      - Create/update/delete your businesses & users if you are a client.
      - Create/subscribe/manage organizations, businesses & users if you are a reseller.
      - Retrieve data on businesses you have access to if you are a publisher.
      - ...
servers:
  - url: https://api.partoo.co/v2
    description: Production server
  - url: https://api.sandbox.partoo.co/v2
    description: Sandbox server (dev environment for clients & partners)
security:
  - ApiKeyAuth: []
paths:
  /reviews:
    post:
      tags:
        - Reviews
      summary: Create and update a review from a custom partner
      description: >
        This endpoint lets you push into Partoo the reviews you collect on your
        own platform,

        through a **custom review partner** enabled on your organization.


        A review is identified by the pair (`partner_slug`, `external_id`):

        - the first call with a given pair **creates** the review,

        - every later call with the same pair **updates** it in place.


        Sending the same payload twice is therefore safe: the second call is a
        no-op and still

        answers `200`. Pushing a review you previously deleted **restores** it.


        You can push for partners that are flagged as `is_custom` by

        [List review partners](/api-reference/reviews/list-review-partners).
        Reviews created this

        way behave like any other review: they are returned by

        [Search for reviews](/api-reference/reviews/search-for-reviews), they
        can be replied to,

        and they trigger the `review_created` / `review_updated` webhooks.


        You must use an API key with `ORG_ADMIN` rights and the `review_edit`
        permission, and the

        business must belong to the organization of the API key's.
      operationId: upsertReview
      requestBody:
        required: true
        content:
          application/json:
            schema:
              description: The review to create or update
              type: object
              required:
                - partner_slug
                - external_id
                - business_id
                - rating
                - author
                - date
              properties:
                partner_slug:
                  type: string
                  minLength: 1
                  maxLength: 100
                  description: >
                    Slug of the custom partner the review comes from.


                    It must be a partner enabled on your organization, returned
                    with

                    `is_custom: true` by [List review
                    partners](/api-reference/reviews/list-review-partners).
                  example: custom_partner
                external_id:
                  type: string
                  minLength: 1
                  maxLength: 255
                  description: >
                    The review's unique id on the source platform. This is the
                    key of the upsert:

                    re-sending the same `external_id` for the same
                    `partner_slug` updates the

                    review instead of creating a new one.


                    It is returned as `key` and `partner_id` on the review. An
                    `external_id`

                    already used by a review of **another** partner is rejected
                    with a `409`.
                  example: ue-review-8f21c0
                business_id:
                  $ref: '#/components/schemas/BusinessId'
                rating:
                  type: integer
                  minimum: 1
                  maximum: 5
                  description: Star rating given by the author.
                  example: 4
                content:
                  type:
                    - string
                    - 'null'
                  maxLength: 4096
                  description: Body of the review. Omit it for a rating-only review.
                  example: Fast delivery, meal was still hot. Thanks !
                author:
                  type: object
                  description: Author of the review, as displayed on the source platform.
                  required:
                    - display_name
                  properties:
                    display_name:
                      type: string
                      minLength: 1
                      maxLength: 255
                      description: >
                        Name displayed for the author. Returned as `author_name`
                        on the review.
                      example: Camille D.
                    is_anonymous:
                      type: boolean
                      default: false
                      description: >
                        Whether the author chose to stay anonymous on the source
                        platform.


                        **Note:** accepted for forward compatibility — it is not
                        stored and not

                        returned on the review today. Use a generic
                        `display_name` for an

                        anonymous author.
                    profile_photo_url:
                      type:
                        - string
                        - 'null'
                      format: uri
                      description: >
                        Public URL of the author's profile picture.


                        **Note:** accepted for forward compatibility — it is not
                        stored and not

                        returned on the review today.
                date:
                  type: string
                  format: date-time
                  description: >
                    When the review was posted on the source platform.


                    The offset is required (for example `+02:00` or `Z`); Partoo
                    stores the date in

                    UTC and renders it in the business timezone.


                    Two reviews of the same business cannot share the same
                    `date` **and**

                    `author.display_name`: such a push answers `409`.
                  example: '2026-09-15T18:32:11+02:00'
                update_date:
                  type: string
                  format: date-time
                  description: >
                    Last update of the review on the source platform. Defaults
                    to `date`, and

                    cannot be earlier than it.
                  example: '2026-09-16T09:04:55+02:00'
                link:
                  type:
                    - string
                    - 'null'
                  format: uri
                  description: Public URL of the review on the source platform.
                  example: https://www.custom_partner.com/reviews/8f21c0
                reply:
                  type:
                    - object
                    - 'null'
                  description: >
                    The reply already published on the source platform, if any.
                    It is created with

                    the review, and updated on a later push carrying a different
                    content or date.


                    Replies written from Partoo are handled by

                    [Post a reply to a
                    review](/api-reference/reviews/post-a-reply-to-a-review)

                    instead.
                  required:
                    - content
                    - date
                  properties:
                    content:
                      type: string
                      minLength: 1
                      maxLength: 4096
                      description: Body of the reply.
                      example: Thank you for your review!
                    date:
                      type: string
                      format: date-time
                      description: >
                        When the reply was posted on the source platform. The
                        offset is required.
                      example: '2026-09-16T09:04:55+02:00'
      responses:
        '200':
          description: The review that was created or updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Review'
        '400':
          $ref: '#/components/responses/400'
        '401':
          $ref: '#/components/responses/401'
        '403':
          description: >
            You are not allowed to perform this action. Either:

            - the API key's user is not an `ORG_ADMIN`, lacks the `review_edit`
            permission, or has
              no write access to the business (`errors.authorization`),
            - or your organization is not enabled for this custom partner
            (`errors.json`).
          content:
            application/json:
              schema:
                type: object
                properties:
                  errors:
                    type: object
                    description: The detail of the error encountered
                    properties:
                      json:
                        type: string
                        example: Your organization cannot push reviews for this partner
                      authorization:
                        type: string
                        example: Operation not allowed
        '404':
          description: >
            Unknown `partner_slug`, a slug that is not a custom partner, unknown
            `business_id`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReviewError'
        '409':
          description: >
            The review conflicts with an existing one. Either the business
            already has a review

            with the same `date` and `author.display_name`, or the `external_id`
            is already used

            by a review of another partner.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReviewError'
        '500':
          description: >
            The review, or its reply, could not be saved. The push is safe to
            retry: it is keyed on

            (`partner_slug`, `external_id`), so a retry never duplicates the
            review.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReviewError'
components:
  schemas:
    BusinessId:
      description: Business id
      type: string
      example: 5409c35a97bbc544d8e26737
    Review:
      description: Business Review on partner
      type: object
      properties:
        key:
          type: string
          description: >
            Identifier of the review on the partner platform. For a review
            pushed through a

            custom partner, this is the `external_id` you sent.
        org_id:
          $ref: '#/components/schemas/OrgId'
        id:
          $ref: '#/components/schemas/ReviewId'
        business_id:
          $ref: '#/components/schemas/BusinessId'
        partner:
          $ref: '#/components/schemas/ReviewPublisherLabel'
        partner_id:
          $ref: '#/components/schemas/ReviewPublisherId'
        author_name:
          $ref: '#/components/schemas/ReviewAuthorName'
        date:
          $ref: '#/components/schemas/ReviewCreateDate'
        update_date:
          $ref: '#/components/schemas/ReviewUpdateDate'
        delete_date:
          $ref: '#/components/schemas/ReviewDeleteDate'
        rating:
          $ref: '#/components/schemas/ReviewRating'
        recommended:
          $ref: '#/components/schemas/ReviewRecommended'
        title:
          $ref: '#/components/schemas/ReviewTitle'
        content:
          $ref: '#/components/schemas/ReviewBody'
        state:
          $ref: '#/components/schemas/ReviewState'
        link:
          $ref: '#/components/schemas/ReviewLink'
        comments:
          type: array
          description: Replies to the review
          items:
            $ref: '#/components/schemas/Comment'
        tags:
          type: array
          description: Tags associated to the review
          items:
            $ref: '#/components/schemas/Tag'
        media_links:
          type: array
          description: >
            Array of Google photo URLs associated with the review.


            Populated when `with_media_links=true` query parameter is used.

            Empty array if no associated media found or if
            `with_media_links=false`.
          items:
            type: string
            format: uri
          example:
            - https://lh3.googleusercontent.com/gpms...
            - https://lh3.googleusercontent.com/gpms-cs-s/AB8u6HYwO...
    ReviewError:
      description: Error returned when a review cannot be pushed or deleted
      type: object
      properties:
        errors:
          type: object
          description: The detail of the error encountered
          properties:
            json:
              type: string
              description: Reason the request was refused
              example: Partner not found
    OrgId:
      description: Unique identifier of an organization in Partoo.
      type: integer
      example: 42
    ReviewId:
      type: integer
      description: Review id
      example: 34
    ReviewPublisherLabel:
      type: string
      description: Review partner slug
      example: google_my_business
    ReviewPublisherId:
      type: string
      description: Review id on publisher
      example: accounts/114063712393225091258/locations/74805271119400652054
    ReviewAuthorName:
      type: string
      description: |
        The author name of the review.

        **Note:** Replies don't have an author.
      example: Castorche
    ReviewCreateDate:
      type: string
      description: Review creation date
      format: datetime
      example: '2017-07-01T16:10:23.156000+02:00'
    ReviewUpdateDate:
      type: string
      description: Review update date
      format: datetime
      example: '2017-08-01T19:15:54.256000+02:00'
    ReviewDeleteDate:
      type: string
      description: Review deletion date (only specified if the review has been deleted)
      format: datetime
    ReviewRating:
      type: integer
      description: Review rating (can be null)
      maximum: 5
      minimum: 0
      example: 3
    ReviewRecommended:
      type: boolean
      description: Review recommended (can be null)
    ReviewTitle:
      type: string
      description: Review title
    ReviewBody:
      type: string
      description: Review body content
      example: >-
        Magasin un peu vieillot , mais personnel très sympathique, nombreuses
        références en rayons , un très bon choix côté vin...
    ReviewState:
      type: string
      description: Reply state
      enum:
        - treated
        - not_treated
        - deleted
    ReviewLink:
      type: string
      format: uri
      description: Link to review on publisher platform
    Comment:
      description: Reply to a review
      type: object
      properties:
        id:
          $ref: '#/components/schemas/CommentId'
        partner_id:
          $ref: '#/components/schemas/ReviewPublisherId'
        created:
          $ref: '#/components/schemas/CreatedDate'
        author_name:
          $ref: '#/components/schemas/ReviewAuthorName'
        content:
          $ref: '#/components/schemas/CommentBody'
        date:
          type: string
          description: Comment date
          format: datetime
          example: '2017-08-01T19:15:54.256000+02:00'
        update_date:
          type: string
          format: datetime
          description: |
            Comment update date. Only specified if the comment was updated
          example: '2017-08-01T19:15:54.256000+02:00'
        can_edit:
          type: boolean
          description: |
            If the current user can or cannot edit a reply

            **Note:** This applies on Facebook replies only.
            A reply left by an external user on Facebook cannot be edited.
          example: true
        review_id:
          $ref: '#/components/schemas/ReviewId'
        parent_id:
          $ref: '#/components/schemas/ParentId'
        user_id:
          type: string
          description: |
            User id of the comment author
          example: 123456789abcdef2f60c42ff
        is_reply_suggestion:
          type: boolean
          description: |
            If AI reply suggestion was used to generate this comment
        replies:
          type: array
          items:
            $ref: '#/components/schemas/Comment'
          description: |
            List of replies to this comment
    Tag:
      description: Tag
      type: object
      properties:
        id:
          $ref: '#/components/schemas/TagId'
        label:
          description: The label of the tag
          allOf:
            - $ref: '#/components/schemas/TagLabel'
        color:
          $ref: '#/components/schemas/TagColor'
    CommentId:
      type: integer
      description: Comment id
      example: 82938
    CreatedDate:
      type: string
      description: Creation date on Partoo
      format: datetime
      example: '2019-08-01T19:15:54.256000+02:00'
    CommentBody:
      type: string
      description: Reply content
      example: Merci ❤️
    ParentId:
      type: integer
      description: |
        id of the parent comment.
        Is only specified if the comment is a reply to another comment

        **Note:** This applies on Facebook replies only.
    TagId:
      description: Tag id
      type: integer
      example: 25
    TagLabel:
      description: >
        The label of the tag

        Must be <= 30 characters and cannot contain a comma (commas will be
        ignored)
      type: string
      example: food
    TagColor:
      description: The color of the tag, in hexadecimal representation
      type: string
      enum:
        - '#808080'
        - '#9B7CDB'
        - '#F47FBE'
        - '#4D4D4D'
        - '#9E6957'
        - '#2F8DE4'
        - '#37CED0'
        - '#53C944'
        - '#B1DA34'
        - '#F78234'
        - '#F4BD38'
        - '#992842'
      example: '#808080'
  responses:
    '400':
      description: Your request is incorrect
      content:
        application/json:
          schema:
            description: |
              Error that occcurs when your request is incorrect
            properties:
              errors:
                type: object
                description: The detail of the error encountered
                properties:
                  json:
                    type: object
    '401':
      description: You are not authenticated
      content:
        application/json:
          schema:
            description: Error that occurs when you are not authenticated
            type: object
            properties:
              errors:
                type: object
                description: The detail of the error encountered
                properties:
                  authentication:
                    type: string
                    default: User not authenticated
  securitySchemes:
    ApiKeyAuth:
      description: >
        The authentication system on Partoo API is using API Key that should be
        put in the header of the request (the name of the header is `x-APIKey`).
        An api_key is linked to a user. This user's role will give you different
        access level to the API features.
      type: apiKey
      in: header
      name: x-APIKey

````