# API key information Source: https://developers.partoo.co/api-reference/apikeys/api-key-information /assets/openapi/openapi-bundled.yaml get /api_keys/{key_id} Given an API key ID, this endpoint gives you information about one key. For more details on how API keys work, and how to handle them securely, see the [Security and API Key Usage](/guides/api/resources/settings/security_and_api_key_usage) guide. # Create API key Source: https://developers.partoo.co/api-reference/apikeys/create-api-key /assets/openapi/openapi-bundled.yaml post /api_keys This endpoint lets you create a new API key. For more details on how API keys work, and how to handle them securely, see the [Security and API Key Usage](/guides/api/resources/settings/security_and_api_key_usage) guide. # List user API keys Source: https://developers.partoo.co/api-reference/apikeys/list-user-api-keys /assets/openapi/openapi-bundled.yaml get /api_keys This endpoint lets you list all the API keys you have access to. For more details on how API keys work, and how to handle them securely, see the [Security and API Key Usage](/guides/api/resources/settings/security_and_api_key_usage) guide. # Revoke API key Source: https://developers.partoo.co/api-reference/apikeys/revoke-api-key /assets/openapi/openapi-bundled.yaml post /api_keys/revoke/{key_id} This endpoint lets you revoke an API key you have access to. For more details on how API keys work, and how to handle them securely, see the [Security and API Key Usage](/guides/api/resources/settings/security_and_api_key_usage) guide. # Update API key Source: https://developers.partoo.co/api-reference/apikeys/update-api-key /assets/openapi/openapi-bundled.yaml put /api_keys/{key_id} This endpoint lets you update an API key you have access to. For more details on how API keys work, and how to handle them securely, see the [Security and API Key Usage](/guides/api/resources/settings/security_and_api_key_usage) guide. # Business fields configuration for a business Source: https://developers.partoo.co/api-reference/business-fields/business-fields-configuration-for-a-business /assets/openapi/openapi-bundled.yaml get /business/{business_id}/business_fields **⚠️ DEPRECATED** This endpoint is deprecated in favor of the new Custom Roles system; for migration information, see the [Custom Roles & Permissions guide](/guides/api/guides/custom-roles-and-permissions). This endpoint gives you the list of all the fields that are available for a given Business. It also tells you, for each field, if you have the permission to edit it or not, depending of the permission configured by your ORG_ADMIN and your PROVIDER. # Business fields configuration for an organization Source: https://developers.partoo.co/api-reference/business-fields/business-fields-configuration-for-an-organization /assets/openapi/openapi-bundled.yaml get /org/{org_id}/business_fields **⚠️ DEPRECATED** This endpoint is deprecated in favor of the new Custom Roles system; for migration information, see the [Custom Roles & Permissions guide](/guides/api/guides/custom-roles-and-permissions). This endpoint provides the list of all fields available for a given organization. For each field, it also indicates: - Whether you have permission to edit it, depending on the permissions configured by the `PROVIDER`. - Whether you have granted permission to edit it for `BUSINESS_MANAGER` and `GROUP_MANAGER` roles who have access to the organization's businesses. Only users with the `ORG_ADMIN` or `PROVIDER` roles can access this information. # Additional data for your business Source: https://developers.partoo.co/api-reference/businesses/additional-data-for-your-business /assets/openapi/openapi-bundled.yaml get /business/{business_id}/additional_data This endpoint lets you access to the additional data of business. You need to have `READ`access on this business. # Business information Source: https://developers.partoo.co/api-reference/businesses/business-information /assets/openapi/openapi-bundled.yaml get /business/{business_id} This endpoint lets you access to the information of a business. You need to have `READ`access on this business. # Create business Source: https://developers.partoo.co/api-reference/businesses/create-business /assets/openapi/openapi-bundled.yaml post /business This API allows the creation of a new business in the context of your organization. # Delete business Source: https://developers.partoo.co/api-reference/businesses/delete-business /assets/openapi/openapi-bundled.yaml delete /business/{business_id} This endpoint lets you delete a business. You need to have `WRITE`access on this business. # Delete Google Food Menus for your business Source: https://developers.partoo.co/api-reference/businesses/delete-google-food-menus-for-your-business /assets/openapi/openapi-bundled.yaml delete /business/{business_id}/food_menus This endpoint allows you to delete the Google Food Menus for your business. # Delete Google Services for your business Source: https://developers.partoo.co/api-reference/businesses/delete-google-services-for-your-business /assets/openapi/openapi-bundled.yaml delete /business/{business_id}/services/{service_id} This endpoint allows you to delete the Google Services set for your business. # Get completion rate stats from your businesses Source: https://developers.partoo.co/api-reference/businesses/get-completion-rate-stats-from-your-businesses /assets/openapi/openapi-bundled.yaml get /business/search/stats This endpoint works in the same way as the [operation/searchBusinesses](/api-reference/businesses/search-for-businesses) endpoint, but instead of returning data on all returned businesses, this endpoint returns completion rate statistics aggregated across all businesses. The statistics returned are the average completion rate for all businesses that fit the given filters, as well as the count of businesses with a low, medium, and high respectively. The thresholds for low, medium, and high can be found below in the response details. Note that this endpoint works in the exact same way as [operation/searchBusinesses](/api-reference/businesses/search-for-businesses) (with the exception of parameters that format the output, such as `order_by` and pagination), but the return value is different. # Get Place Action Links Source: https://developers.partoo.co/api-reference/businesses/get-place-action-links /assets/openapi/openapi-bundled.yaml get /business/{business_id}/place_action_links Retrieve a list of place action links for a given business_id. Only the available gmb_id links for the business are returned in the GET request. Additionally, the business must be connected to a Google location. For more details, refer to the [Partner Connection](https://app.partoo.co/settings/platforms/connection) page. # Google attributes for your business Source: https://developers.partoo.co/api-reference/businesses/google-attributes-for-your-business /assets/openapi/openapi-bundled.yaml get /business/{business_id}/attributes This endpoint allows you to view the **Google attributes** set for your business. # Google Food Menus for your business Source: https://developers.partoo.co/api-reference/businesses/google-food-menus-for-your-business /assets/openapi/openapi-bundled.yaml get /business/{business_id}/food_menus This endpoint allows you to view the Google Food Menus set for your business. # Google Lodging attributes for your business Source: https://developers.partoo.co/api-reference/businesses/google-lodging-attributes-for-your-business /assets/openapi/openapi-bundled.yaml get /business/{business_id}/lodging This endpoint allows you to view the **Google Lodging attributes** set for your business. The business must be accessible by the authenticated user and the user must have the `business_edit_attributes` permission. If the business Google location cannot operate Lodging data, `lodging` is `null`. If the location can operate Lodging data but no Lodging attribute value is set yet, `lodging` is an empty array. # Google Services for your business Source: https://developers.partoo.co/api-reference/businesses/google-services-for-your-business /assets/openapi/openapi-bundled.yaml get /business/{business_id}/services This endpoint allows you to view the Google Services set for your business. # More hours for your business Source: https://developers.partoo.co/api-reference/businesses/more-hours-for-your-business /assets/openapi/openapi-bundled.yaml get /business/{business_id}/more_hours This endpoint allows you to view the **More Hours** set for your business. # Search for businesses Source: https://developers.partoo.co/api-reference/businesses/search-for-businesses /assets/openapi/openapi-bundled.yaml get /business/search This lets you search among the businesses you have `READ` access to. You can use several filters. The response is paginated (30 results per page). # Set additional data for your business Source: https://developers.partoo.co/api-reference/businesses/set-additional-data-for-your-business /assets/openapi/openapi-bundled.yaml post /business/{business_id}/additional_data This endpoint lets you set additional data on a business. You need to have `WRITE` access on this business. Additional is a flat object with at most 10 keys. # Set custom Google Services for your business Source: https://developers.partoo.co/api-reference/businesses/set-custom-google-services-for-your-business /assets/openapi/openapi-bundled.yaml post /business/{business_id}/free_form_services This endpoint allows you to set or update custom Google Services for your business. # Set Google attributes for your business Source: https://developers.partoo.co/api-reference/businesses/set-google-attributes-for-your-business /assets/openapi/openapi-bundled.yaml post /business/{business_id}/attributes This endpoint allows you to set **Google attributes** for your business. # Set Google Food Menus for your business Source: https://developers.partoo.co/api-reference/businesses/set-google-food-menus-for-your-business /assets/openapi/openapi-bundled.yaml post /business/{business_id}/food_menus This endpoint allows you to set or update Google Food Menus for your business. # Set Google Lodging attributes for your business Source: https://developers.partoo.co/api-reference/businesses/set-google-lodging-attributes-for-your-business /assets/openapi/openapi-bundled.yaml post /business/{business_id}/lodging This endpoint allows you to partially set or update **Google Lodging attributes** for your business. Only lodging attributes included in the request body are updated. Other existing lodging attributes are left unchanged. The business Google location must be able to operate Lodging data. For each lodging attribute, provide either a `value` or an `exception`, but not both. Attributes returned by `GET /v2/lodging/list` with `read_only: true` cannot be modified. Sending a read-only lodging attribute in this request returns a `400` error. # Set Google Services for your business Source: https://developers.partoo.co/api-reference/businesses/set-google-services-for-your-business /assets/openapi/openapi-bundled.yaml post /business/{business_id}/structured_services This endpoint allows you to set or update Google Services for your business. When you set a service of type STRUCTURED_SERVICE_ITEM for a category, every category that have this service available will also have it set for them. # Set more hours for your business Source: https://developers.partoo.co/api-reference/businesses/set-more-hours-for-your-business /assets/openapi/openapi-bundled.yaml post /business/{business_id}/more_hours This endpoint allows you to set the **More Hours** for your business. # Set Place Action Links Source: https://developers.partoo.co/api-reference/businesses/set-place-action-links /assets/openapi/openapi-bundled.yaml post /business/{business_id}/place_action_links This endpoint enables you to manage place action links for a given business. Create, update, or delete place action links by modifying the urls array for each gmb_id. - Create: Include a place action link in urls without an id. - Update: Include the given place action link in urls with an existing id. - Delete: Omit the specific link object from urls or provide an empty urls array to remove all for the gmb_id . For the POST method, ensure you send the complete list of desired links to retain or update per gmb_id. # Statistics for your connected businesses Source: https://developers.partoo.co/api-reference/businesses/statistics-for-your-connected-businesses /assets/openapi/openapi-bundled.yaml get /business/connections_stats This endpoint lets you access the number of businesses connected to different platforms. # Subscribe a business Source: https://developers.partoo.co/api-reference/businesses/subscribe-a-business /assets/openapi/openapi-bundled.yaml post /business/{business_id}/subscribe ⚠️ This endpoint is deprecated. Please use the new endpoint [`/business/{business_id}/plans`](/api-reference/subscriptions/update-businesss-plans) instead. ⚠️ This endpoint lets you subscribe a business to one or several Partoo products. You need to have `WRITE` access on the business you want to subscribe. You need to have `PROVIDER` to be able to perform this action. # Subscriptions for your business Source: https://developers.partoo.co/api-reference/businesses/subscriptions-for-your-business /assets/openapi/openapi-bundled.yaml get /business/{business_id}/subscription ⚠️ This endpoint is deprecated. Please use the new endpoint [`/business/{business_id}/plans`](/api-reference/subscriptions/update-businesss-plans) instead. ⚠️ This endpoint lets you access the subscription of a business. You need to have `READ` access on this business. # Unsubscribe a business Source: https://developers.partoo.co/api-reference/businesses/unsubscribe-a-business /assets/openapi/openapi-bundled.yaml post /business/{business_id}/unsubscribe ⚠️ This endpoint is deprecated. Please use the new endpoint [`/business/{business_id}/plans`](/api-reference/subscriptions/update-businesss-plans) instead. ⚠️ This endpoint lets you unsubscribe a business from one or several Partoo products. You need to have `WRITE` access on the business you want to subscribe. You need to have `PROVIDER` to be able to perform this action. # Update business Source: https://developers.partoo.co/api-reference/businesses/update-business /assets/openapi/openapi-bundled.yaml post /business/{business_id} This endpoint lets you access to the information of a business. You need to have `WRITE` access on this business. Only indicated values are taken into account (it works like a `PATCH`). You cannot push fields disabled for your org. # Category information Source: https://developers.partoo.co/api-reference/categories/category-information /assets/openapi/openapi-bundled.yaml get /categories/{category_id} This endpoint lets you retrieve the data of a specific category. # List Partoo categories Source: https://developers.partoo.co/api-reference/categories/list-partoo-categories /assets/openapi/openapi-bundled.yaml get /categories This endpoint lets you read and filter through Partoo categories. # Suggested additional categories Source: https://developers.partoo.co/api-reference/categories/suggested-additional-categories /assets/openapi/openapi-bundled.yaml get /categories/{category_id}/suggestions This endpoint lets you retrieve Partoo's suggestions for additional categories, based on a given category. # Check connection token Source: https://developers.partoo.co/api-reference/connection-tokens/check-connection-token /assets/openapi/openapi-bundled.yaml get /connection/check_token This endpoint lets you check the status of a connection token. To be able to check a connection token of a user, you need to have `WRITE` access on that user. # Generate connection token Source: https://developers.partoo.co/api-reference/connection-tokens/generate-connection-token /assets/openapi/openapi-bundled.yaml post /connection/generate_token This endpoint lets you generate a connection token to authenticate a user without having to indicate its credentials. To be able to generate a connection token for a user, you need to have `WRITE` access on that user and that user cannot have `PROVIDER` role. A connection token is valid only once and has a time to live of maximum one day. # Revoke connection token Source: https://developers.partoo.co/api-reference/connection-tokens/revoke-connection-token /assets/openapi/openapi-bundled.yaml post /connection/revoke_token This endpoint lets you revoke a connection token. To be able to revoke a connection token for a user, you need to have `WRITE` access on that user and the connection token must be valid (not expired, not revoked and not consumed). # Ingest message Source: https://developers.partoo.co/api-reference/custom-channels/ingest-message /assets/openapi/openapi-bundled.yaml post /custom-channels/{channel_id}/messages This endpoint lets you ingest messages in conversations that use custom channels. When called, it creates a new message in the specified conversation. If the conversation does not exist, the endpoint will automatically create the conversation before adding the message. You must use an API key with `ORG_ADMIN` or `PROVIDER` rights for this endpoint. ⚠️ A `200 OK` response does not guarantee that the message was successfully created. It only means the request was received and accepted for processing. ⚠️ # Create custom field sections Source: https://developers.partoo.co/api-reference/custom-fields-section/create-custom-field-sections /assets/openapi/openapi-bundled.yaml post /custom_fields/section This endpoint enables you to create custom field sections for your organization. You can specify a name, optional description, slug, and order. If no order is provided, it will be set to max(all current sections orders) + 1. `PROVIDER` users can pass `org_id` to create custom field sections for a managed organization. # Delete custom field section Source: https://developers.partoo.co/api-reference/custom-fields-section/delete-custom-field-section /assets/openapi/openapi-bundled.yaml delete /custom_fields/section/{section_id} This endpoint enables you to delete a specific custom field section of your organization. All custom fields in the section will be moved to no section (section_id = null). `PROVIDER` users can pass `org_id` to delete custom field sections for a managed organization. # Get custom field sections Source: https://developers.partoo.co/api-reference/custom-fields-section/get-custom-field-sections /assets/openapi/openapi-bundled.yaml get /custom_fields/section Retrieve list of custom fields sections for a given organization, including their names, descriptions, slugs, and ordering information. # Update custom field sections Source: https://developers.partoo.co/api-reference/custom-fields-section/update-custom-field-sections /assets/openapi/openapi-bundled.yaml put /custom_fields/section/{section_id} This endpoint enables you to update a specific custom field section of their organization. You can update the name, description, and slug of the section. `PROVIDER` users can pass `org_id` to update custom field sections for a managed organization. # Create custom fields Source: https://developers.partoo.co/api-reference/custom-fields/create-custom-fields /assets/openapi/openapi-bundled.yaml post /custom_fields This endpoint enables you to create custom fields for your organization. You can specify the field name, description, slug, type-specific constraints, order, and optionally assign it to a section. `PROVIDER` users can pass `org_id` to create custom fields for a managed organization. # Delete custom field Source: https://developers.partoo.co/api-reference/custom-fields/delete-custom-field /assets/openapi/openapi-bundled.yaml delete /custom_fields/{custom_field_id} This endpoint enables you to delete a specific custom field of your organization by specifying its ID. Use the `force` parameter to delete fields that have values assigned to businesses. `PROVIDER` users can pass `org_id` to delete a custom field for a managed organization. # Get custom fields Source: https://developers.partoo.co/api-reference/custom-fields/get-custom-fields /assets/openapi/openapi-bundled.yaml get /custom_fields This endpoint enables you to get custom fields for your organization, including their names, descriptions, types, constraints, section associations, and slugs. # Order custom fields Source: https://developers.partoo.co/api-reference/custom-fields/order-custom-fields /assets/openapi/openapi-bundled.yaml post /custom_fields/order This endpoint enables you to reorganize the order of custom fields and custom field sections within your organization. You can also move custom fields between sections by specifying a different section_id. `PROVIDER` users can pass `org_id` to reorder custom fields for a managed organization. # Update custom field Source: https://developers.partoo.co/api-reference/custom-fields/update-custom-field /assets/openapi/openapi-bundled.yaml put /custom_fields/{custom_field_id} This endpoint enables you to update a specific custom field of your organization by specifying its ID. You can update the **name**, **description**, **slug**, **constraints**, and **section assignment** of the custom field. However, the **type** of a custom field cannot be modified. Use the `force` parameter to apply changes that might conflict with existing business data. `PROVIDER` users can pass `org_id` to update a custom field for a managed organization. # Create Custom Role Source: https://developers.partoo.co/api-reference/custom-roles/create-custom-role /assets/openapi/openapi-bundled.yaml post /custom_role This endpoint enables you to create custom roles for organizations within your scope. # Delete Custom Role Source: https://developers.partoo.co/api-reference/custom-roles/delete-custom-role /assets/openapi/openapi-bundled.yaml delete /custom_role/{custom_role_api_id} This endpoint enables you to delete custom roles for organizations within your scope. # Duplicate Custom Role Source: https://developers.partoo.co/api-reference/custom-roles/duplicate-custom-role /assets/openapi/openapi-bundled.yaml post /custom_role/duplicate Duplicate a Custom Role. A new Custom Role with (almost) the same `name` and `api_id`, and identical `description` and `permissions` will be created in your organization. The new `name` will be the same as the original role, with an added suffix - `"My Custom Role"` → `"My Custom Role - 2"` And similar for the `api_id`: - `"my_custom_role"` → `"my_custom_role_2"` # Get Custom Role Source: https://developers.partoo.co/api-reference/custom-roles/get-custom-role /assets/openapi/openapi-bundled.yaml get /custom_role/{custom_role_api_id} Get the details of a specific Custom Role. # Get Custom Roles switch status Source: https://developers.partoo.co/api-reference/custom-roles/get-custom-roles-switch-status /assets/openapi/openapi-bundled.yaml get /org/{org_id}/switch_to_custom_roles Get the current status of the organization's switch to Custom Roles. This endpoint returns information about whether the organization has switched to Custom Roles and whether they are allowed to switch. # Get Permissions Source: https://developers.partoo.co/api-reference/custom-roles/get-permissions /assets/openapi/openapi-bundled.yaml get /permissions This endpoint will give you all of the permissions available to your organization. The permissions are categorized by section, and by subsection. The permissions available to your organization are based on the plans your organization subscribes to; and thus the features included in those plans. # List Custom Roles Source: https://developers.partoo.co/api-reference/custom-roles/list-custom-roles /assets/openapi/openapi-bundled.yaml get /custom_role Get all Custom Roles for your organization. # Switch to Custom Roles Source: https://developers.partoo.co/api-reference/custom-roles/switch-to-custom-roles /assets/openapi/openapi-bundled.yaml post /org/{org_id}/switch_to_custom_roles Update the organization's Custom Roles switch status. This endpoint allows you to enable or disable the Custom Roles feature for the organization, provided the organization is allowed to make this change. # Update Custom Role Source: https://developers.partoo.co/api-reference/custom-roles/update-custom-role /assets/openapi/openapi-bundled.yaml post /custom_role/{custom_role_api_id} Update a Custom Role, allowing you to set the `name`, `api_id`, `description`, and `permissions` of an already existing Custom Role. # Feedback analytics metrics Source: https://developers.partoo.co/api-reference/feedback-analytics/feedback-analytics-metrics /assets/openapi/openapi-bundled.yaml get /feedback/analytics/metrics **⚠️ This feature is available only for organisations subscribed to Feedback Management. ⚠️** Retrieve aggregated feedback analytics data for your organisation. A request is composed of: - One or more **`metrics`** — the data you want to compute (required) - An optional **`dimensions`** — how the data is grouped - If omitted, the request returns the aggregated totals across all data matching the filters - An optional **`order_by`** — how the rows are sorted - **Filters** to narrow the data: - By business (`business__in`, `business__notin`) - By group or group section (`groups`, `group_section_id`) - By date range (`filter_date__gte`, `filter_date__lte`) - By survey or field (`survey__in`, `survey_field__in`, `survey_field_type__in`) - By NPS score (`result_nps_score__in`) - By free-text comment (`verbatim_query`) - By data quality issues (`issues__in`, `issues__notin`) - By business location (`city`, `query`) **Metrics** are grouped into five categories: | Category | Prefix | Examples | |---|---|---| | Survey | `survey.` | `survey.response_rate`, `survey.nb__sent` | | CSAT | `result.csat.` | `result.csat.score`, `result.csat.avg_score` | | NPS | `result.nps.` | `result.nps.score`, `result.nps.promoters` | | Response | `response.` | `response.avg_response_time`, `response.method.nb__ai` | | Result field | `result_field.` | `result_field.rating`, `result_field.choices` | **Dimensions** control how rows are grouped: - Entity: `business`, `user`, `feedback_form`, `group`, `group_section`, `feedback_form_field`, `result` - Time: `day`, `month`, `year` **Excel download**: add `download=true` to receive the data as an `.xlsx` file instead of JSON. Use `table_name` to customise the filename. **Metadata**: add `metadata=true` to include full entity objects (businesses, forms, users…) alongside the `data` array. Useful for resolving IDs to display names without extra API calls. # Create an email template Source: https://developers.partoo.co/api-reference/feedback-management/create-an-email-template /assets/openapi/openapi-bundled.yaml post /feedback/email-templates The Feedback Management API is currently in **BETA**, therefore the following endpoints are subject to modification, given a **2 week notice**. If you are planning to use any of them, please **notify us** so we will be able to keep you informed about upcoming changes. Creates a new feedback email template for the authenticated user's organization. When `cta_type` is `BUTTON`, the `cta_text` field is required. # Delete an email template Source: https://developers.partoo.co/api-reference/feedback-management/delete-an-email-template /assets/openapi/openapi-bundled.yaml delete /feedback/email-templates/{template_id} The Feedback Management API is currently in **BETA**, therefore the following endpoints are subject to modification, given a **2 week notice**. If you are planning to use any of them, please **notify us** so we will be able to keep you informed about upcoming changes. Deletes a feedback email template belonging to the authenticated user's organization. # Fetch AI reply suggestion for feedback results Source: https://developers.partoo.co/api-reference/feedback-management/fetch-ai-reply-suggestion-for-feedback-results /assets/openapi/openapi-bundled.yaml get /feedback/feedback_result/fetch-suggestion/{feedback_result_id}/{index} The Feedback Management API is currently in **BETA**, therefore the following endpoints are subject to modification, given a **2 week notice**. If you are planning to use any of them, please **notify us** so we will be able to keep you informed about upcoming changes. Fetch a reply suggestion generated by AI for a specific feedback result. # Get a feedback result by ID Source: https://developers.partoo.co/api-reference/feedback-management/get-a-feedback-result-by-id /assets/openapi/openapi-bundled.yaml get /feedback/feedback_result/{feedback_result_id} The Feedback Management API is currently in **BETA**, therefore the following endpoints are subject to modification, given a **2 week notice**. If you are planning to use any of them, please **notify us** so we will be able to keep you informed about upcoming changes. This endpoint lets you retrieve a single feedback result by its ID. # Get campaign requirements Source: https://developers.partoo.co/api-reference/feedback-management/get-campaign-requirements /assets/openapi/openapi-bundled.yaml get /feedback/campaign/requirements The Feedback Management API is currently in **BETA**, therefore the following endpoints are subject to modification, given a **2 week notice**. If you are planning to use any of them, please **notify us** so we will be able to keep you informed about upcoming changes. Returns the recipient fields and template variables needed to prepare a feedback email campaign for the given feedback form and email template. Use this endpoint before [Send a feedback email campaign](/api-reference/feedback-management/send-a-feedback-email-campaign) to determine which keys to include in each recipient payload. # List email templates Source: https://developers.partoo.co/api-reference/feedback-management/list-email-templates /assets/openapi/openapi-bundled.yaml get /feedback/email-templates The Feedback Management API is currently in **BETA**, therefore the following endpoints are subject to modification, given a **2 week notice**. If you are planning to use any of them, please **notify us** so we will be able to keep you informed about upcoming changes. Retrieves the paginated list of feedback email templates for the authenticated user's organization, ordered by most recently updated. The response is paginated (default 30 results per page, up to 100). # Push email-delivery stats for a feedback form Source: https://developers.partoo.co/api-reference/feedback-management/push-email-delivery-stats-for-a-feedback-form /assets/openapi/openapi-bundled.yaml post /feedback/feedback_form/stats The Feedback Management API is currently in **BETA**, therefore the following endpoints are subject to modification, given a **2 week notice**. If you are planning to use any of them, please **notify us** so we will be able to keep you informed about upcoming changes. This endpoint lets you push one day of email-delivery funnel metrics (sent, delivered, opened, clicked, bounced) for a feedback form and business, typically reported by your Email Service Provider (ESP). It upserts on `(feedback_form_id, business_id, date)`: `sent` and `clicked` always overwrite the row, while the optional metrics (`processed`, `delivered`, `opened`, `bounced`) keep their previous value when omitted or `null`, defaulting to `0` only on a brand-new row. Rows created here are always stored with `source: external`, and feed the `survey.sent`, `survey.delivered`, `survey.opened`, `survey.clicked` and `survey.error_bounces` [analytics metrics](/api-reference/feedback-analytics/feedback-analytics-metrics). # Reply to a feedback result Source: https://developers.partoo.co/api-reference/feedback-management/reply-to-a-feedback-result /assets/openapi/openapi-bundled.yaml post /feedback/feedback_result/{feedback_result_id}/reply The Feedback Management API is currently in **BETA**, therefore the following endpoints are subject to modification, given a **2 week notice**. If you are planning to use any of them, please **notify us** so we will be able to keep you informed about upcoming changes. This endpoint lets you reply to a feedback result. In order to be able to reply to a feedback result: - The `optin` property of the corresponding feedback result must be true - The `email_reply_source` of the corresponding feedback form must be set - The `email_reply_subject` of the corresponding feedback form must be set # Search for feedback forms Source: https://developers.partoo.co/api-reference/feedback-management/search-for-feedback-forms /assets/openapi/openapi-bundled.yaml get /feedback/feedback_form The Feedback Management API is currently in **BETA**, therefore the following endpoints are subject to modification, given a **2 week notice**. If you are planning to use any of them, please **notify us** so we will be able to keep you informed about upcoming changes. This endpoint lets you search for the feedback forms of your organization. The response is paginated (30 results per page). # Search for feedback results Source: https://developers.partoo.co/api-reference/feedback-management/search-for-feedback-results /assets/openapi/openapi-bundled.yaml get /feedback/feedback_result The Feedback Management API is currently in **BETA**, therefore the following endpoints are subject to modification, given a **2 week notice**. If you are planning to use any of them, please **notify us** so we will be able to keep you informed about upcoming changes. This endpoint lets you search for the feedback results of your businesses. The response is paginated (30 results per page). # Send a feedback email campaign Source: https://developers.partoo.co/api-reference/feedback-management/send-a-feedback-email-campaign /assets/openapi/openapi-bundled.yaml post /feedback/campaign/send Validates the sender email, validates recipients, and sends a feedback email campaign to the provided recipient list. Use the [Get campaign requirements](/api-reference/feedback-management/get-campaign-requirements) endpoint to retrieve the variables each recipient must provide. The sender email domain must be authorized for your organization and validated for email sending. If sender validation fails, the entire campaign is rejected and the response includes `sender_validation` details. If any recipient fails validation, the entire campaign is rejected and **no emails are sent**. The response body details every validation error. Set `is_dry_run: true` to validate recipients without sending any emails. # Update a feedback form Source: https://developers.partoo.co/api-reference/feedback-management/update-a-feedback-form /assets/openapi/openapi-bundled.yaml put /feedback/feedback_form/{feedback_form_id} The Feedback Management API is currently in **BETA**, therefore the following endpoints are subject to modification, given a **2 week notice**. If you are planning to use any of them, please **notify us** so we will be able to keep you informed about upcoming changes. This endpoint lets you modify the properties of your feedback forms. # Update an email template Source: https://developers.partoo.co/api-reference/feedback-management/update-an-email-template /assets/openapi/openapi-bundled.yaml put /feedback/email-templates/{template_id} The Feedback Management API is currently in **BETA**, therefore the following endpoints are subject to modification, given a **2 week notice**. If you are planning to use any of them, please **notify us** so we will be able to keep you informed about upcoming changes. Updates an existing feedback email template belonging to the authenticated user's organization. All fields are optional — only the fields present in the request body are updated. When the resulting `cta_type` is `BUTTON` (either newly set or already stored), `cta_text` must be non-null. # Complete Google Location Verification Process Source: https://developers.partoo.co/api-reference/google/complete-google-location-verification-process /assets/openapi/openapi-bundled.yaml post /verifications/google-locations/{google_location_id}/complete This endpoint completes the Google location verification process identified by `google_location_id`. It requires authentication and authorization with at least the role of `BUSINESS_MANAGER`. If the verification process is not in the `PENDING` status, or if the PIN code is invalid, an error response will be returned. If the completion is successful, the verification status of the location will be updated. # Details on a specific Google Location Source: https://developers.partoo.co/api-reference/google/details-on-a-specific-google-location /assets/openapi/openapi-bundled.yaml get /google-oauth-accounts/locations/{google_location_id} Returns a Google location object that corresponds to the given google_location_id. The google_location_id is a unique identifier on Partoo for each location. This endpoint requires authentication, and only authorized users with the appropriate permissions can access it. # Fetch Google Location Verification Options Source: https://developers.partoo.co/api-reference/google/fetch-google-location-verification-options /assets/openapi/openapi-bundled.yaml get /verifications/google-locations/{google_location_id}/options This endpoint retrieves verification options for a specific Google location identified by `google_location_id`. It requires authentication and authorization to access. The user must have at least the role of a `BUSINESS_MANAGER` to use this endpoint. Note that the response can return an empty options list, this can mean two things: - There are really no verification options available for this location. - Video verification is possible but not implemented through the API. In this case, you should ask the user to manually verify. # List Google Attributes Source: https://developers.partoo.co/api-reference/google/list-google-attributes /assets/openapi/openapi-bundled.yaml get /attributes/list Get all Google Attributes available for a Category in a given language. ⚠️ **What are Google Attributes?** Google Attributes are highly visible statements about your business that appear on your Google listing. They indicate things like Payment Options, Amenities, Accessibility and Highlights. Does a business provide parking? Does it have a fireplace? Can customers pay with a debit card? To recover attributes values set for a business, [see get attributes business endpoints](/api-reference/businesses/google-attributes-for-your-business). To handle attributes values for businesses, [see set attributes business endpoints](/api-reference/businesses/set-google-attributes-for-your-business). This endpoint allows you to view the **Google** attributes available for a given Category. # List Google Lodging attributes Source: https://developers.partoo.co/api-reference/google/list-google-lodging-attributes /assets/openapi/openapi-bundled.yaml get /lodging/list Get all Google Lodging attributes available in Partoo. Google Lodging attributes describe hotel-specific information such as property features, services, policies, amenities, and guest unit details. The response is grouped by lodging section. Each attribute definition gives the Google attribute id, its type, display order, available enum options when relevant, whether an exception code can be used instead of a value, and whether the attribute is read-only. Attributes marked with `read_only: true` are returned for display purposes only and cannot be modified through `POST /v2/business/{business_id}/lodging`. # List Google more hours Source: https://developers.partoo.co/api-reference/google/list-google-more-hours /assets/openapi/openapi-bundled.yaml get /more_hours/list ⚠️ **What are Google More Hours?** More Hours is a feature in *Google* that allows the business owner to display hours for specific services available. Examples of such services include opening hours for the kitchen, for breakfast, for happy hour, etc. Notice that the available More Hour IDs vary between both business categories and countries. For example, a restaurant will have different More Hour IDs available than a bank, and a restaurant in France will have different IDs available than a restaurant in the USA. To recover More Hours set for a business, see [Get More Hours for your Business endpoints](/api-reference/businesses/more-hours-for-your-business). To handle More Hours for businesses, see [Update More Hours for your Business endpoints](/api-reference/businesses/set-more-hours-for-your-business). This endpoint allows you to get all the different **More Hour IDs** available for a given business category, including their translated names for the given language. # List Google Services Source: https://developers.partoo.co/api-reference/google/list-google-services /assets/openapi/openapi-bundled.yaml get /services/suggestions Get all Google Services available for your business categories. ⚠️ **What are Google Services?** Google Services are highly visible statements about your business that appear on your Google listing. They indicate the different services available for your business, to which you can also add a price and a description. For example, the category `gcid:bakery` has several suggested services available, such as catering or delivery. Not satisfied with those? You can add your very own custom services and link them to the category of your business of your choice! To recover service values set for a business, see [get services business endpoints](/api-reference/businesses/google-services-for-your-business). To handle service values for businesses, see [set structured services business endpoints](/api-reference/businesses/set-google-attributes-for-your-business). To handle custom service values for businesses, see [set free form services business endpoints](/api-reference/businesses/set-custom-google-services-for-your-business). This endpoint allows you to view the Google Services available for your business. The services available depend on the categories of the business, not only the main one. # Search for Google locations Source: https://developers.partoo.co/api-reference/google/search-for-google-locations /assets/openapi/openapi-bundled.yaml get /google-oauth-accounts/locations/search Performs a search for Google locations based on the provided query parameters. This endpoint requires authentication, and only authorized users with the appropriate permissions can access it. # Start Google Location Verification Process Source: https://developers.partoo.co/api-reference/google/start-google-location-verification-process /assets/openapi/openapi-bundled.yaml post /verifications/google-locations/{google_location_id}/start This endpoint initiates the verification process for a specific Google location identified by `google_location_id`. It requires authentication and authorization to access. The user must have at least the role of a `BUSINESS_MANAGER` to use this endpoint. The endpoint ensures that the chosen verification method has all the necessary information for the specific method chosen. If any required information is missing, it raises an error with the associated error message. # Create Group and set businesses Source: https://developers.partoo.co/api-reference/groups-and-sections/create-group-and-set-businesses /assets/openapi/openapi-bundled.yaml post /sections/{section_id}/groups Create a new group. This endpoint allows `Group Managers` to create new groups within the system. For more information about the group system, see [the Groups and Sections description](/guides/api/resources/organizations/groups). ⚠️ You must specify which businesses are part of the group using the `business__in` parameter. - If you don't specify any businesses, the group will be created with **all** businesses. - To create an empty group, provide an empty array in the `business__in` parameter. # Create Section Source: https://developers.partoo.co/api-reference/groups-and-sections/create-section /assets/openapi/openapi-bundled.yaml post /sections Create a new section. This endpoint endpoint let's you create a new section. Only Group Managers and above can use this endpoint. Business Managers are restricted from accessing this endpoint. For more information about the group system, see [the Groups and Sections description](/guides/api/resources/organizations/groups). # Delete Group Source: https://developers.partoo.co/api-reference/groups-and-sections/delete-group /assets/openapi/openapi-bundled.yaml delete /sections/{section_id}/groups/{group_id} Delete a group. This endpoint endpoint let's you delete an existing group. Only Group Managers and above can use this endpoint. Business Managers are restricted from accessing this endpoint. For more information about the group system, see [the Groups and Sections description](/guides/api/resources/organizations/groups). # Delete Section Source: https://developers.partoo.co/api-reference/groups-and-sections/delete-section /assets/openapi/openapi-bundled.yaml delete /sections/{section_id} Delete a section. This endpoint endpoint let's you delete an existing section. Only Group Managers and above can use this endpoint. Business Managers are restricted from accessing this endpoint. For more information about the group system, see [the Groups and Sections description](/guides/api/resources/organizations/groups). # Get Group Source: https://developers.partoo.co/api-reference/groups-and-sections/get-group /assets/openapi/openapi-bundled.yaml get /sections/{section_id}/groups/{group_id} Get a group and it's associated business IDs. For more information about the group system, see [the Groups and Sections description](/guides/api/resources/organizations/groups). # Get Section by ID Source: https://developers.partoo.co/api-reference/groups-and-sections/get-section-by-id /assets/openapi/openapi-bundled.yaml get /sections/{section_id} Get a single section. For more information about the group system, see [the Groups and Sections description](/guides/api/resources/organizations/groups). # Get Sections Source: https://developers.partoo.co/api-reference/groups-and-sections/get-sections /assets/openapi/openapi-bundled.yaml get /sections Get all the sections for an organization. For more information about the group system, see [the Groups and Sections description](/guides/api/resources/organizations/groups). # Update Group and set businesses Source: https://developers.partoo.co/api-reference/groups-and-sections/update-group-and-set-businesses /assets/openapi/openapi-bundled.yaml post /sections/{section_id}/groups/{group_id} Update a group. This endpoint allows you to modify the details of an existing group within the system. Only `Group Managers` and higher roles can use this endpoint. `Business Managers` are restricted from accessing it. For more information about the group system, see [the Groups and Sections description](/guides/api/resources/organizations/groups). ⚠️ You must specify which businesses are part of the group using the `business__in` parameter. - If you don't specify any businesses, the group will be updated to include **all** businesses. - To update a group to be empty, provide an empty array in the `business__in` parameter. # Update Section Source: https://developers.partoo.co/api-reference/groups-and-sections/update-section /assets/openapi/openapi-bundled.yaml post /sections/{section_id} Update the name of a section. This endpoint endpoint let's you update an existing section. Only Group Managers and above can use this endpoint. Business Managers are restricted from accessing this endpoint. For more information about the group system, see [the Groups and Sections description](/guides/api/resources/organizations/groups). # Get holidays Source: https://developers.partoo.co/api-reference/holidays/get-holidays /assets/openapi/openapi-bundled.yaml get /holidays/{country} This endpoint allows you to retrieve a list of upcoming bank holidays for a specified country within the next 365 days. The holidays are ordered based on their occurrence dates. # Create message template Source: https://developers.partoo.co/api-reference/message-reply-templates/create-message-template /assets/openapi/openapi-bundled.yaml post /messaging/templates This endpoint lets you create a new message template. ⚠️ The content should be a valid __stringified JSON__ object. It has to include both the `"text"` key with the message content and the pair `"_version": "0.1"`. # Delete message template Source: https://developers.partoo.co/api-reference/message-reply-templates/delete-message-template /assets/openapi/openapi-bundled.yaml delete /messaging/templates/{template_id} This endpoint lets you delete a message template given its ID. # List message templates Source: https://developers.partoo.co/api-reference/message-reply-templates/list-message-templates /assets/openapi/openapi-bundled.yaml get /messaging/templates This endpoint retrieves the list of message templates for the current user's organization. # Update message template Source: https://developers.partoo.co/api-reference/message-reply-templates/update-message-template /assets/openapi/openapi-bundled.yaml put /messaging/templates/{template_id} This endpoint allows updating an existing message template by its ID. # Conversation information Source: https://developers.partoo.co/api-reference/messages/conversation-information /assets/openapi/openapi-bundled.yaml get /conversations/{conversation_id} This endpoint returns all information on a specific Conversation. # List conversations Source: https://developers.partoo.co/api-reference/messages/list-conversations /assets/openapi/openapi-bundled.yaml get /conversations This endpoint lets you list all the Conversations you have access to. You can filter the conversations based on the Organization or the Business that they are related to. If you want to keep an up-to-date list of ongoing conversations for your businesses, we recommend using the [Message Received](/api-reference/webhooks-events/message-created) and [Message Deleted](#operation/message_deleted) Webhooks instead of periodically calling this endpoint. ⚠️ This endpoint is paginated using cursor pagination. This means that in order to get the next page of results, you need to provide the cursor returned in the previous call. # List messages Source: https://developers.partoo.co/api-reference/messages/list-messages /assets/openapi/openapi-bundled.yaml get /messages This endpoint lets you retrieve the messages for a specific conversation. ⚠️ This endpoint is paginated using cursor pagination. This means that in order to get the next page of results, you need to provide the cursor returned in the previous call. # Read conversation Source: https://developers.partoo.co/api-reference/messages/read-conversation /assets/openapi/openapi-bundled.yaml post /conversations/{conversation_id}/read This endpoint lets you mark a conversation as read. It will be set for the user that performs the request ("is_read" may have different values for different users). # Retry send message Source: https://developers.partoo.co/api-reference/messages/retry-send-message /assets/openapi/openapi-bundled.yaml post /messages/{message_id}/retry This endpoint let you retry sending a message that has failed to be sent. # Send message Source: https://developers.partoo.co/api-reference/messages/send-message /assets/openapi/openapi-bundled.yaml post /messages This endpoint allows you to send a message as a business, in an existing conversation. The supported content types when sending messages are : - Text - Image - Video - Audio - Document ⚠️ Due to underlying channel limitations, some media content_types are not supported on all channels :
Channel Image Video Audio Document
Facebook ✅ ✅ ✅ ✅
Instagram ✅ ✅ ✅ ❌
SMS ❌ ❌ ❌ ❌
Whatsapp ✅ ✅ ✅ ✅
When dealing with media messages (`Image`, `Video`, `Audio`, `Document`), there are some additionnal file type and file size limitations. - Image size should not exceed 5 MB. - Video size should not exceed 16 MB. - Audio size should not exceed 16 MB. - Document size should not exceed 100 MB. For optimal support, you should target the following file types : - Image : `jpeg`, `png`. - Video : `mp4`. - Audio : `aac`, `mp4`. - Document : `xls`, `xlsx`, `docx`, `pdf`, `ppt`, `pptx`. A successful HTTP response to this endpoint (code 200) does not necessarily mean that the message has been correctly delivered to the consumer, only that it has been created on Partoo. To ensure that the message has been delivered successfully, we recommend subscribing to the [Message Updated](/api-reference/webhooks-events/message-updated) Webhook, and checking that the `status` field of the message has switched to `Success`. If the answer has failed to be sent, you can send it again by using the [/retry endpoint](/api-reference/messages/retry-send-message) # Update conversation Source: https://developers.partoo.co/api-reference/messages/update-conversation /assets/openapi/openapi-bundled.yaml post /conversations/{conversation_id} Please use POST /conversations/{conversation_id}/read or PATCH /conversations/{conversation_id} instead. The only updatable field is "is_read". It will be set for the user that performs the request ("is_read" may have different values for different users). # Update conversation Source: https://developers.partoo.co/api-reference/messages/update-conversation-1 /assets/openapi/openapi-bundled.yaml patch /conversations/{conversation_id} This endpoint lets you change the status of the conversation to "open"/"closed" or to assign it to a user. ⚠️ You can only perform one action at a time: either change the status or assign a user. # List messaging settings Source: https://developers.partoo.co/api-reference/messaging-settings/list-messaging-settings /assets/openapi/openapi-bundled.yaml get /messaging/settings This endpoint lets you list all the Messaging Settings you have access to. You can filter the Messaging Settings based on the Organization or the Business that they are related to. # Update messaging settings Source: https://developers.partoo.co/api-reference/messaging-settings/update-messaging-settings /assets/openapi/openapi-bundled.yaml post /messaging/settings/{setting_id} This endpoint lets you update a specific Messaging Settings. # Create organization Source: https://developers.partoo.co/api-reference/organizations/create-organization /assets/openapi/openapi-bundled.yaml post /org This endpoint lets you create an organization. You have `WRITE` access on your provider (ie. only possible if you have `PROVIDER` role). # Delete organization Source: https://developers.partoo.co/api-reference/organizations/delete-organization /assets/openapi/openapi-bundled.yaml delete /org/{org_id} This endpoint lets you delete an organization. You need to have `WRITE` access on your provider. When an organization gets deleted all the resources linked to it are deleted (users and businesses). If the organization still has businesses or users, it would raise an error if you do not indicate `force="True"` in the JSON body. # Organization information Source: https://developers.partoo.co/api-reference/organizations/organization-information /assets/openapi/openapi-bundled.yaml get /org/{org_id} This endpoint lets you retrieve all the detail about a specific organization. You need to have `READ` access to this organization. # Search for organizations Source: https://developers.partoo.co/api-reference/organizations/search-for-organizations /assets/openapi/openapi-bundled.yaml get /org/search This endpoint lets you search for organizations using filters. The response is paginated (30 results per page). # Update organization Source: https://developers.partoo.co/api-reference/organizations/update-organization /assets/openapi/openapi-bundled.yaml post /org/{org_id} This endpoint lets you update the information of an organization. You need to have `WRITE` access on the organization. # Get Place Action Links Source: https://developers.partoo.co/api-reference/place-action-links/get-place-action-links /assets/openapi/openapi-bundled.yaml get /place_action_links Retrieve a list of available place action links. # Create a post Source: https://developers.partoo.co/api-reference/posts/create-a-post /assets/openapi/openapi-bundled.yaml post /posts This endpoint lets you create a post or a draft post on Google / Facebook / Instagram. The creation of a post will not happen in real time and might take a few minutes. A draft post can only be created by Org Admins and is not immediately published. An expiration date must be specified when creating a draft post. In order to be published, a draft needs to be updated by a BM/GM user before the expiration date. # Delete a post Source: https://developers.partoo.co/api-reference/posts/delete-a-post /assets/openapi/openapi-bundled.yaml delete /posts/{post_id} This endpoint lets you delete a post. The deletion will not happen in real time and might take a few minutes. ⚠️ Due to Instagram API limitations, **this operation has no effect on Instagram posts.** # Search for post Source: https://developers.partoo.co/api-reference/posts/search-for-post /assets/openapi/openapi-bundled.yaml get /posts This endpoint lets you browse through all your posts. # Update a post Source: https://developers.partoo.co/api-reference/posts/update-a-post /assets/openapi/openapi-bundled.yaml put /posts/{post_id} This endpoint lets you update a post. When used by a BM or GM user, this endpoint also serves to validate and publish a draft post. The update will not happen in real time and might take a few minutes ⚠️ Due to Instagram API limitations, **this operation has no effect on Instagram posts**. # Profile keywords for your business Source: https://developers.partoo.co/api-reference/presence-analytics/profile-keywords-for-your-business /assets/openapi/openapi-bundled.yaml get /presence_analytics/keywords This endpoint lets you view the monthly **Google Business Profile** search keywords for all your businesses subscribed to Presence Management. To access the analytics of a business, you need to: - have `READ` access on it - have subscribed to **Presence Management** for this business. - You can access the search keywords from **Google Business Profile**. The analytics on search keywords are made available by Google Business Profile on a monthly basis. You will receive the following metrics: - count: The sum of the number of unique users that used the keyword in a month - threshold: A threshold value indicating that the actual value is less than the threshold. Google Business Profile typically displays for search keywords that were used less than 15 times in a month. You can use the following filters: - by businesses (businesses id in list, and restricted to one business when using the keyword dimension.) - by date (analytics before and/or after a date) - by branded status (branded vs discovery keywords) The response can be aggregated by: - business id - by date: month or year - by keyword - by branded status (branded vs discovery) The response can be ordered by: - business id - by date: month, or year - by keyword - by branded status The response can be ordered in ascending or descending order by any of the selected dimensions or metrics. # Profile metrics for your business Source: https://developers.partoo.co/api-reference/presence-analytics/profile-metrics-for-your-business /assets/openapi/openapi-bundled.yaml get /presence_analytics/metrics This endpoint lets you view the **Google Business Profile** analytics for all your businesses subscribed to **Presence Management**. The API allows you to select what data you're interested in, and how you want it aggregated (daily, monthly, by business, etc). You can also filter the results to limit it to a certain date range, and to certain business. Google Business Profile doesn't provide reliable data for the most recent 5 days. You can choose the analytics you want to get among: - impressions: desktop maps impressions, mobile maps impressions, desktop search impressions, and mobile search impressions - actions: website link clicks, phone calls, and driving directions You can use the following filters: - by businesses (businesses id in list or not in list) - by date (analytics before and/or after a date) - by business query. Will return matches for the business name, zipcode or city - by business city. The response can be aggregated by: - business id - by date: either by day, week, month or year - by both business id and date The response can be ordered in ascending or descending order by any of the selected dimensions or metrics. See examples for more details. # Get diffusion errors for a business Source: https://developers.partoo.co/api-reference/presence/get-diffusion-errors-for-a-business /assets/openapi/openapi-bundled.yaml post /diffusion_errors/{business_id} Get diffusion errors for a given business. This endpoint returns diffusion errors grouped by publisher. Diffusion errors are classified into two types: - **Pre-check errors**: errors detected *before* sending data to partners, based on the current business data. - **Post-check errors**: errors detected *after* sending data to partners, based on partner responses. ### Behavior - If no input parameters are provided: - Returns the **existing** pre-check and post-check errors stored in the database. - If input parameters are provided: - Applies the provided fields as an in-memory update on the business (without persisting). - Recalculates pre-check errors based on these changes. - Post-check errors are **not** recalculated in this case. ### Example Use Case Use this endpoint during a business edit form to validate which publishers would be affected by a change, without saving it yet. # PublisherErrors (DEPRECATED) Source: https://developers.partoo.co/api-reference/presence/publishererrors-deprecated /assets/openapi/openapi-bundled.yaml post /publisher_errors/{business_id} ⚠️ **DEPRECATED** - Please use [`POST /v2/diffusion_errors/{business_id}`](/api-reference/presence/get-diffusion-errors-for-a-business) instead. This method retrieve a list of known errors associated with a publisher for a business, including detailed descriptions. The request body is mandatory. Providing an empty request body will return errors based on the business information stored in the database. Providing a populated request body will return errors related to the specified fields and their values only. # PublisherStates Source: https://developers.partoo.co/api-reference/presence/publisherstates /assets/openapi/openapi-bundled.yaml get /publisher_states Method to retrieve businesses diffusions states on publishers. Can be filtered by: - Business IDs - Publishers - States # Get Review metrics Source: https://developers.partoo.co/api-reference/review-analytics/get-review-metrics /assets/openapi/openapi-bundled.yaml get /review_analytics/metrics **⚠️ This feature is available only for businesses subscribed to Review Management. ⚠️** All the operations to perform Reviews analytics. This endpoint lets you view the statistics related to reviews made to your businesses subscribed to **Review Management**. A request is composed of: - One or more `metrics` which is the data you want to return - An optional `dimensions` which defines how the data is grouped by - If it is omitted, the request will return the metrics over all the data, based on your filters - An optional `order_by` to define how the data is sorted - Filters, the data can be filtered by: - Businesses - Groups - Tags - Review update date Here is the list of all **metrics** available: - `average_rating`: Average rating - `rating_distribution`: Breakdown of the ratings (Number of 1-star reviews, 2-star reviews, 3-star reviews, etc...) - `reviews_count`: Number of reviews received - `reply_time`: Breakdown of the reviews based on how fast (less or more than 48 hours) they have been replied to (or not replied) - `reply_means`: Breakdown of the review replies based on the reply method used (manual reply, reply template, auto reply or AI suggestion) - `average_rating_distribution`: Breakdown of your businesses based on their average rating - `rank`: Allows you to rank the users, businesses or groups based on their performance on a metric (an order_by is required) Here is the list of all **dimensions** available, and for each of them, the list of metrics and sort order available: - No dimension - This allows you to get global stats across all your businesses - Available metrics: `average_rating`, `rating_distribution`, `reviews_count`, `reply_time`, `reply_means`, `average_rating_distribution` - Date dimensions: `day`, `week`, `month`, `year` - This allows you to get the evolution of your metrics over time - Available metrics: `average_rating`, `rating_distribution`, `reviews_count`, `reply_time`, `reply_means` - Business and business group dimensions: `business`, `group` - This allows you to see the metrics business by business or group by group (Requires group filter) - Available metrics: `average_rating`, `rating_distribution`, `reviews_count`, `reply_time`, `reply_means`, `rank` - `user` - This allows you to see the metrics user by user - Available metrics: `reply_time`, `reply_means`, `rank` - `tag` - This allows you to see the metrics tag by tag - Available metrics: `average_rating`, `rating_distribution`, `reviews_count` Here is the list of all **order_by** available (Add a minus `-` sign before to order by decreasing order): - `average_rating`: Sort by average rating - `reviews_count`: Sort by review_count - `reply_time__total`: Sort by number of reviews received - `reply_means__total`: Sort by number of reviews that have been replied - `ratio__rating_distribution__5`: Sort by the ratio of 5 star reviews - `ratio__rating_distribution__negative`: Sort by the ratio of negative reviews - `ratio__reply_time__fast`: Sort by the ratio of reviews replied in less than 2 days - `ratio__reply_time__slow`: Sort by the ratio of reviews replied in more than 2 days - `ratio__reply_time__not_replied`: Sort by the ratio of reviews not replied - `ratio__reply_means__manual`: Sort by the ratio reviews replied manually - `ratio__reply_means__ai_suggestion`: Sort by the ratio reviews replied using AI suggestion - `ratio__reply_means__reply_template`: Sort by the ratio reviews replied using reply template - `ratio__reply_means__auto_reply`: Sort by the ratio reviews replied using auto reply To use an **order_by** parameter, its corresponding metric must be included in the request. (i.e. to order by `average_rating`, you must include the `average_rating` metric in the `metrics` parameter, to order by `ratio__rating_distribution__5`, you must include the `rating_distribution` metric in the `metrics` parameter, and so on...) # Global reviews statistics Source: https://developers.partoo.co/api-reference/review-analytics/global-reviews-statistics /assets/openapi/openapi-bundled.yaml get /reviews/stats This endpoint let you view the global reviews statistics for all your businesses subscribed to **Review Management**. You can use the following filters: - by date (statistics before and/or after a date) - by businesses (businesses id in list or not in list) - by keywords The response is aggregated according to the previously selected filters. In order to get analytics evolution overtime returned by specific time range, please refer to **Qualitative Evolution** and **Quantitative Evolution** endpoints. # Qualitative evolution Source: https://developers.partoo.co/api-reference/review-analytics/qualitative-evolution /assets/openapi/openapi-bundled.yaml get /reviews/qualitative-evolution This endpoint lets you view the qualitative evolution of the **reviews rating** for all of your businesses subscribed to **Review Management**. The API returns the reviews average rating by bucket (time range). You can use the following filters: - by date (analytics before and/or after a date) - by businesses (businesses id in list or not in list) - by keywords # Quantitative evolution Source: https://developers.partoo.co/api-reference/review-analytics/quantitative-evolution /assets/openapi/openapi-bundled.yaml get /reviews/quantitative-evolution This endpoint lets you view the quantitative evolution of the **number of reviews** for all of your businesses subscribed to **Review Management**. The API returns the cumulative sum of the number of reviews by bucket (time range) selected overtime. You can use the following filters: - by date (analytics before and/or after a date) - by businesses (businesses id in list or not in list) - by keywords # Search for an invitation matching a set of criteria Source: https://developers.partoo.co/api-reference/review-booster/search-for-an-invitation-matching-a-set-of-criteria /assets/openapi/openapi-bundled.yaml get /review_booster/search-invitation This endpoint allows to fetch previously sent invitations. Your access token must be for an user subscribed to the Review Booster product to access this route. The user must have access to the business. This can be useful to avoid sending multiple invitations to the same user in a defined period. # Send a review invitation Source: https://developers.partoo.co/api-reference/review-booster/send-a-review-invitation /assets/openapi/openapi-bundled.yaml post /review_booster/send_invitation This endpoint lets you send an SMS to a customer to help them leave a message on Google. You need to have `WRITE` access on the business. You can add `invite_content` in your payload to customize the SMS content that will be received by the recipient. Otherwise, the template associated with the user will be used. If no template exists, a new one will be generated. Your business needs to be connected to a Google location and subscribed to the Review Booster product. Therefore, this cannot be tested in the Sandbox environment. To prevent spamming, a new SMS can be sent to a specific phone number only after 10 days since the last SMS was sent. # Set the expeditor name of a business Source: https://developers.partoo.co/api-reference/review-booster/set-the-expeditor-name-of-a-business /assets/openapi/openapi-bundled.yaml post /review_booster/expeditor This endpoint lets you set the expeditor name of a business. An expeditor name is the name of the sender used to send the message. It will be seen instead of the phone number on the destination phone. An expeditor name's length must be between 3 and 11 characters. No special characters are allowed. Your business must be subscribed to the Review Booster product. # Template for a user Source: https://developers.partoo.co/api-reference/review-booster/template-for-a-user /assets/openapi/openapi-bundled.yaml get /review_booster/template This endpoint lets you get your corresponding template. If no template exists for the user, a template is created and sent back. You need to be subscribed to the Review Booster product. # The expeditor name of a business Source: https://developers.partoo.co/api-reference/review-booster/the-expeditor-name-of-a-business /assets/openapi/openapi-bundled.yaml get /review_booster/expeditor This endpoint lets you get the expeditor name of a business. An expeditor name is the name of the sender used to send the message. It will be seen instead of the phone number on the destination phone. Your business must be subscribed to the Review Booster product. # The status of a review invitation Source: https://developers.partoo.co/api-reference/review-booster/the-status-of-a-review-invitation /assets/openapi/openapi-bundled.yaml get /review_booster/invitation_status This endpoint allows to get the status about an invitation sent through the Review Booster. Your access token must be for a user subscribed to the Review Booster. The invitation id must be for a business for which the user has access to. # Update the template of a user Source: https://developers.partoo.co/api-reference/review-booster/update-the-template-of-a-user /assets/openapi/openapi-bundled.yaml put /review_booster/template This endpoint lets you update the template associated with the user. 3 placeholders are available for the template: `${client_name}`, `${business_name}`, and `${url}`. There are 2 main constraints: - `${url}` must be present in the template sent. - The text should not contain more than 250 characters (excluding placeholders). The template must exist before the request is sent. You need to be subscribed to the Review Booster product. # All available placeholders Source: https://developers.partoo.co/api-reference/reviews/all-available-placeholders /assets/openapi/openapi-bundled.yaml get /reviews/templates/placeholders This endpoint lets you access available placeholders for reply review templates. A template placeholder is a dynamically updated word within the Partoo app depending on the context. Ex: Once used to answer a review, if a template has a `client_first_name` placeholder, the placeholder will take the value of the reviewer's first name. # Create a review reply template Source: https://developers.partoo.co/api-reference/reviews/create-a-review-reply-template /assets/openapi/openapi-bundled.yaml post /reviews/template This endpoint lets you create a review reply template. # Create and update a review from a custom partner Source: https://developers.partoo.co/api-reference/reviews/create-and-update-a-review-from-a-custom-partner /assets/openapi/openapi-bundled.yaml post /reviews 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. # Delete a review from a custom partner Source: https://developers.partoo.co/api-reference/reviews/delete-a-review-from-a-custom-partner /assets/openapi/openapi-bundled.yaml delete /reviews/{review_id} This endpoint lets you delete a review your organization pushed through a **custom review partner**. Reviews synchronized natively by Partoo (Google, Facebook, TripAdvisor…) cannot be deleted this way. The deletion is a soft one: the review is kept with `state: deleted` and its author masked, which is what lets a later [push of the same `external_id`](/api-reference/reviews/push-a-review-from-a-custom-partner) bring it back. Deleted reviews are excluded from statistics, and from searches that filter them out with `state__notin=deleted`. Deleting a review you already deleted answers `204` as well, so a retry is always safe. The `review_updated` webhook fires on the first deletion only. You must use an API key with `ORG_ADMIN` rights and the `review_edit` permission. # Delete a review reply template Source: https://developers.partoo.co/api-reference/reviews/delete-a-review-reply-template /assets/openapi/openapi-bundled.yaml delete /reviews/template/{template_id} This endpoint lets you delete a review reply template given its id. # Delete the given reply to a review Source: https://developers.partoo.co/api-reference/reviews/delete-the-given-reply-to-a-review /assets/openapi/openapi-bundled.yaml delete /comments/{comment_id} This endpoint lets you delete the reply to a review # Fetch AI reply suggestion for reviews Source: https://developers.partoo.co/api-reference/reviews/fetch-ai-reply-suggestion-for-reviews /assets/openapi/openapi-bundled.yaml get /reviews/fetch-suggestion/{review_id}/{index} The AI reply suggestion is a service that generates a response to a review based on the review content. ⚠️ This feature provides reply SUGGESTIONS, NOT AUTOMATIC REPLIES. It is NOT designed for fully automating conversations. Similar to the app, a human reviewer is expected to validate the suggestion before selecting it in order to use [reply to a review](/api-reference/reviews/post-a-reply-to-a-review) endpoint ⚠️ **How does the AI reply suggestion work?** - First, call the Fetch AI reply suggestion service. - Then retrieve the values and store them on the caller's side. It is possible to request up to 3 suggestions per reply, and after that, it's no longer possible; the suggestions are retained once they're made, and that they can be found at the `index` (0, 1, or 2) of the parameters - Finally, use the suggestion ID and pass it to `reply_suggestion` request body when calling the [reply to a review](/api-reference/reviews/post-a-reply-to-a-review) service to link the response to the suggestion. # List review partners Source: https://developers.partoo.co/api-reference/reviews/list-review-partners /assets/openapi/openapi-bundled.yaml get /review-partners This endpoint lists the partners whose reviews you can work with, and is the source of the slugs used in the `partner` field of a review and in the `partner__in` search filter. It returns: - `google_my_business` and `facebook`, always, - `tripadvisor`, when at least one business you have access to is connected to TripAdvisor, - the **custom partners** enabled on your organization, flagged with `is_custom: true`. Only the businesses you have `READ` access to and subscribed to review management are taken into account. # Modify a reply to a review Source: https://developers.partoo.co/api-reference/reviews/modify-a-reply-to-a-review /assets/openapi/openapi-bundled.yaml put /comments/{comment_id} This endpoint lets you modify a given reply to a review. # Post a reply to a review Source: https://developers.partoo.co/api-reference/reviews/post-a-reply-to-a-review /assets/openapi/openapi-bundled.yaml post /comments This endpoint lets you reply to a given review. # Search for review reply templates Source: https://developers.partoo.co/api-reference/reviews/search-for-review-reply-templates /assets/openapi/openapi-bundled.yaml get /reviews/templates/search This endpoint lets you browse through all your reply review templates. # Search for reviews Source: https://developers.partoo.co/api-reference/reviews/search-for-reviews /assets/openapi/openapi-bundled.yaml get /reviews This endpoint lets you search for the reviews of your businesses. To access the reviews of a business you need to have `READ` access on it. The response is paginated (30 results per page). By default, no state filter is applied: the response includes **all** reviews, including deleted ones. Use `state__in` / `state__notin` to narrow the result. # Update a review Source: https://developers.partoo.co/api-reference/reviews/update-a-review /assets/openapi/openapi-bundled.yaml put /reviews/{review_id} Update the state of a review to treated/not_treated # Get Business's plans Source: https://developers.partoo.co/api-reference/subscriptions/get-businesss-plans /assets/openapi/openapi-bundled.yaml get /business/{business_id}/plans This endpoint lets you retrieve the business's plans.
You need to be a Provider to access this endpoint. # Get Organization's plans Source: https://developers.partoo.co/api-reference/subscriptions/get-organizations-plans /assets/openapi/openapi-bundled.yaml get /org/{org_id}/plans This endpoint lets you retrieve the organization's plans. You need to be a Provider to access this endpoint. # Update business's plans Source: https://developers.partoo.co/api-reference/subscriptions/update-businesss-plans /assets/openapi/openapi-bundled.yaml post /business/{business_id}/plans This endpoint lets you update the plans of a business.
You need to be a Provider to access this endpoint.
⚠️You need to send all the plans, those not sent will be removed. We advise you to call the GET endpoint first. ⚠️ # Update organization's plans Source: https://developers.partoo.co/api-reference/subscriptions/update-organizations-plans /assets/openapi/openapi-bundled.yaml post /org/{org_id}/plans This endpoint lets you update the plans of an organization. You need to be a Provider to access this endpoint. ⚠️ You need to send **all the plans**, those not sent will be removed. We advise you to call the GET endpoint first. ⚠️ # Create user Source: https://developers.partoo.co/api-reference/users/create-user /assets/openapi/openapi-bundled.yaml post /user This endpoint lets you create a user. If no password given, a password will automatically be generated. The password will be ignored if `send_invitation` is set to `True`. You need to have `WRITE` access on the organization of the user you want to create. If you want to have an `invited` user but send the invitation email later, you have to send the `send_invitation` parameter as `False` and a `status` parameter to `invited`. You will then have to call the [invitation endpoint](/api-reference/users/invite-user) to send the invitation email to the user. # Delete user Source: https://developers.partoo.co/api-reference/users/delete-user /assets/openapi/openapi-bundled.yaml delete /user/{user_id} This endpoint lets you delete a user. You need to have `WRITE` access to this user. # Invite user Source: https://developers.partoo.co/api-reference/users/invite-user /assets/openapi/openapi-bundled.yaml post /user/{user_id}/invite This endpoint lets you trigger a new invitation email to an `invited` user. You need to have `WRITE` access to this user. The email can only be sent once every 5 minutes. # My user Source: https://developers.partoo.co/api-reference/users/my-user /assets/openapi/openapi-bundled.yaml get /user/me This endpoint lets you retrieve all the information about your user # Search for users Source: https://developers.partoo.co/api-reference/users/search-for-users /assets/openapi/openapi-bundled.yaml get /user/search This endpoint lets you search for users using filters # Set user preferences Source: https://developers.partoo.co/api-reference/users/set-user-preferences /assets/openapi/openapi-bundled.yaml post /user/{user_id}/preferences This endpoint lets you update all the information about a user's preferences on notifications. You need to have `WRITE` access to this user. # Update user Source: https://developers.partoo.co/api-reference/users/update-user /assets/openapi/openapi-bundled.yaml post /user/{user_id} This endpoint lets you update a user. You need to have `WRITE` access to this user. It has a patch behaviour which means that only indicated value will be changed. # User businesses Source: https://developers.partoo.co/api-reference/users/user-businesses /assets/openapi/openapi-bundled.yaml get /user/{user_id}/businesses This endpoint lets you retrieve the list of businesses which the selected user has `READ` access to. # User information Source: https://developers.partoo.co/api-reference/users/user-information /assets/openapi/openapi-bundled.yaml get /user/{user_id} This endpoint lets you retrieve all the information on a user. You need to have `READ` access to this users. # User preferences Source: https://developers.partoo.co/api-reference/users/user-preferences /assets/openapi/openapi-bundled.yaml get /user/{user_id}/preferences This endpoint lets you retrieve all the information about a user's preferences on notifications. You need to have `READ` access to this user. Here are the default values for newly created users ```json { "reports": { "review_management_daily": true, "review_management_weekly": true, "review_management_monthly": true, "daily_review_preferences": { "partners": [ "google_my_business", "facebook" ], "review_type": 2 } }, "receive_negative_reviews_email_notifications": false } ``` # Business deleted Source: https://developers.partoo.co/api-reference/webhooks-events/business-deleted /assets/openapi/openapi-bundled.yaml webhook businessDeleted This event is triggered when a Business is removed from Partoo Database. The event payload contains the event type and the business id. # Business updated Source: https://developers.partoo.co/api-reference/webhooks-events/business-updated /assets/openapi/openapi-bundled.yaml webhook businessUpdated This event is triggered when a Business is updated in Partoo Database. The event payload contains the event type and the business contents. Attention, the hook may be triggered on internal changes that may not reflect on the contents sent. # Custom review reply created Source: https://developers.partoo.co/api-reference/webhooks-events/custom-review-reply-created /assets/openapi/openapi-bundled.yaml webhook customReplyCreated This event is triggered when a reply is written in Partoo on a review created for a [custom review partner](/guides/api/resources/reviews/retrieve-reviews#custom-review-partners). # Custom review reply deleted Source: https://developers.partoo.co/api-reference/webhooks-events/custom-review-reply-deleted /assets/openapi/openapi-bundled.yaml webhook customReplyDeleted This event is triggered when a reply is removed in Partoo from a review you pushed through a [custom review partner](/guides/api/resources/reviews/retrieve-reviews#custom-review-partners). # Custom review reply updated Source: https://developers.partoo.co/api-reference/webhooks-events/custom-review-reply-updated /assets/openapi/openapi-bundled.yaml webhook customReplyUpdated This event is triggered when an existing reply is edited in Partoo on a review you pushed through a [custom review partner](/guides/api/resources/reviews/retrieve-reviews#custom-review-partners). # Email opt out created Source: https://developers.partoo.co/api-reference/webhooks-events/email-opt-out-created /assets/openapi/openapi-bundled.yaml webhook emailOptOutCreated This event is triggered when a recipient opts out of survey emails. The event payload contains the event timestamp and the opted-out email address. # Lead received Source: https://developers.partoo.co/api-reference/webhooks-events/lead-received /assets/openapi/openapi-bundled.yaml webhook leadReceived This event is triggered when a Lead is added in Partoo Database. The event payload contains the event type and the lead contents. # Message created Source: https://developers.partoo.co/api-reference/webhooks-events/message-created /assets/openapi/openapi-bundled.yaml webhook messageCreated This event is triggered when a conversation has a new message. The event payload contains the event type, the content of the message created, and additional information about the conversation. # Message updated Source: https://developers.partoo.co/api-reference/webhooks-events/message-updated /assets/openapi/openapi-bundled.yaml webhook messageUpdated This event is triggered if the field of a message is updated (example: `status`, `is_deleted`). Messages send via Partoo are created with the status `Sending`, and propagated to the messaging channel. If the message is sent successfully, the status is changed to `Success`. If the messaging channel fails to send the message, the status changed to `Failed`. A failed message can be retried using the [/retry endpoint](/api-reference/messages/retry-send-message). The event payload contains the event type, the content of the updated message and additional information about the conversation. # New business created Source: https://developers.partoo.co/api-reference/webhooks-events/new-business-created /assets/openapi/openapi-bundled.yaml webhook businessCreated This event is triggered when a Business is created in Partoo Database. The event payload contains the event type and the business contents. # Review created Source: https://developers.partoo.co/api-reference/webhooks-events/review-created /assets/openapi/openapi-bundled.yaml webhook reviewCreated This event is triggered when a business receives a new review. The event payload contains the event type and the review contents. # Review reply created Source: https://developers.partoo.co/api-reference/webhooks-events/review-reply-created /assets/openapi/openapi-bundled.yaml webhook reviewReplyCreated This event is triggered when a review has been replied to. The event payload contains the event type and the reply contents. # Review reply deleted Source: https://developers.partoo.co/api-reference/webhooks-events/review-reply-deleted /assets/openapi/openapi-bundled.yaml webhook reviewReplyDeleted This event is triggered when a review reply has been deleted The event payload contains the review reply id. # Review reply updated Source: https://developers.partoo.co/api-reference/webhooks-events/review-reply-updated /assets/openapi/openapi-bundled.yaml webhook reviewReplyUpdated This event is triggered when a review reply has been updated. The event payload contains the event type and the reply contents. # Review updated Source: https://developers.partoo.co/api-reference/webhooks-events/review-updated /assets/openapi/openapi-bundled.yaml webhook reviewUpdated This event is triggered when a review is updated. This can happen in one of these cases: - One or more attributes of a review have been updated (including a content or rating update from its author) - A tag has been assigned or unassigned to this review on Partoo - A review has been deleted - this could happen in two ways (see more info below): - Permanently, by the author. - Temporarily unavailable due to a bug in Google’s system - If a review reappears after being temporarily unavailable ⚠️ **More info on review deletes:** Because of a bug in Google’s system, some reviews may temporarily disappear from their data as if they were deleted, even though they were not, and then reappear later. When a review goes missing, we cannot determine whether it was actually deleted or just affected by this bug. We must consider this review as if it can reappear in the future. For that reason, a `review_updated` event will be sent in both cases. Here is a sample scenario: - September 4: A review is edited by its author. - A `review_update` event is triggered, showing the review updated content. - September 10: The review disappears due to the Google bug. - Another `review_update` event is triggered, with the review state set at `deleted` - September 15: The review becomes visible again. - Another `review_update` is then triggered, showing the review state before the soft delete # Create webhook configurations Source: https://developers.partoo.co/api-reference/webhooks/create-webhook-configurations /assets/openapi/openapi-bundled.yaml post /webhooks This endpoint create webhook configurations. # Delete a webhook configuration Source: https://developers.partoo.co/api-reference/webhooks/delete-a-webhook-configuration /assets/openapi/openapi-bundled.yaml delete /webhooks/{webhook_id} This endpoint deletes a webhook configuration. # Get a list of webhook configurations Source: https://developers.partoo.co/api-reference/webhooks/get-a-list-of-webhook-configurations /assets/openapi/openapi-bundled.yaml get /webhooks This endpoint returns the list of webhook configurations. # Get a webhook configuration Source: https://developers.partoo.co/api-reference/webhooks/get-a-webhook-configuration /assets/openapi/openapi-bundled.yaml get /webhooks/{webhook_id} This endpoint returns the details of a webhook configuration. # List available webhook events Source: https://developers.partoo.co/api-reference/webhooks/list-available-webhook-events /assets/openapi/openapi-bundled.yaml get /webhooks/events This endpoint returns the list of the webhook events available to the organization, depending on the subscribed products. # Send test webhook payloads Source: https://developers.partoo.co/api-reference/webhooks/send-test-webhook-payloads /assets/openapi/openapi-bundled.yaml post /webhooks/tryout This endpoint let you try webhook configurations by sending test payloads. This currently supports only one webhook configuration per request, entries after the first one will be ignored. Payloads are created by the latest data of the specified event type, or if not available a default payload will be sent. The request is similar to a regular webhook, but also contains an additional `X-Partoo-Webhook-Tryout` header. # Update a webhook configuration Source: https://developers.partoo.co/api-reference/webhooks/update-a-webhook-configuration /assets/openapi/openapi-bundled.yaml patch /webhooks/{webhook_id} This endpoint updates a webhook configuration. # Breaking Changes Source: https://developers.partoo.co/changelogs/api/breaking-changes This page provides information about breaking changes to the API. **📅 How to read this page** Each breaking change shows two dates: * The **date on the left** is when the change was **communicated**. * The **yellow tag** is when the change **takes effect**. Breaking changes are listed with the latest effective date first. ⚠️ Takes effect 15th October 2026 ### Deprecation of publisher\_errors endpoint The [`POST /publisher_errors/{business_id}`](/api-reference/presence/publishererrors-deprecated) endpoint has been deprecated in favor of the new [`POST /diffusion_errors/{business_id}`](/api-reference/presence/get-diffusion-errors-for-a-business) endpoint. **What's changing:** * The old [`POST /publisher_errors/{business_id}`](/api-reference/presence/publishererrors-deprecated) endpoint is now marked as deprecated * Please migrate to the new [`POST /diffusion_errors/{business_id}`](/api-reference/presence/get-diffusion-errors-for-a-business) endpoint **Why this change:** * Better organization and consolidation of publisher error handling endpoints * Improved feature control with proper authorization checks * More comprehensive error handling and validation **Migration guide:** Update your API calls from: ```bash theme={null} POST /publisher_errors/{business_id} ``` To: ```bash theme={null} POST /diffusion_errors/{business_id} ``` The response structure has changed. The new endpoint provides errors grouped by publisher with enhanced categorization (pre-check and post-check errors). Review the examples below. **Old response format (publisher\_errors):** ```json theme={null} { "errors": [ { "publisher_id": "google", "error_code": "le118000", "field": "invalid_field", "message": "Field validation failed" } ] } ``` **New response format (diffusion\_errors):** ```json theme={null} { "diffusion_errors": { "google": { "pre_check_errors": [ { "error_code": "le118000", "field": "invalid_field", "message": "Field validation failed" } ], "post_check_errors": [] } } } ``` Review the [diffusion errors endpoint documentation](/api-reference/presence/get-diffusion-errors-for-a-business) for complete details on the new response structure. ⚠️ Takes effect 15th July 2026 ### Deprecation of business fields endpoints and `sidebar_pages` The legacy permission system — **Business Fields** and **Sidebar Pages** — is being replaced by the new [Custom Roles](/guides/api/guides/custom-roles-and-permissions) system. **You are affected if:** * You read business-field permissions through the `business_fields` endpoints * You control sidebar visibility through the `sidebar_pages` user parameter **Deprecated endpoints:** * [`GET /org/{org_id}/business_fields`](/api-reference/business-fields/business-fields-configuration-for-an-organization) — organization-level business fields * [`GET /business/{business_id}/business_fields`](/api-reference/business-fields/business-fields-configuration-for-a-business) — business-level business fields If you used `GET /org/{org_id}/business_fields` to retrieve the organization's list of custom fields, use [`GET /v2/custom_fields`](/api-reference/custom-fields/get-custom-fields) instead. **Deprecated user parameter:** * `sidebar_pages` — replaced by the Custom Roles `permissions` model. Seen in: * [`POST /v2/user`](/api-reference/users/create-user) (create user) * [`POST /v2/user/{user_id}`](/api-reference/users/update-user) (update user) When creating or updating a user without a `custom_role`, users with the `GROUP_MANAGER` or `BUSINESS_MANAGER` role are automatically assigned the default built-in Custom Role associated with their role. **What happens on the effective date:** There will be no data loss until 15th July 2026 — your legacy permission data is preserved and you can switch back at any time. On the effective date, any organization that hasn't migrated yet is **migrated automatically** by Partoo, and the legacy permission data is then permanently deleted: * Your Business Field permissions are applied to the **built-in roles** (*Business Manager* and *Group Manager*). * Where users have specific Sidebar Pages, the matching **Custom Roles are created automatically**. You don't need to recreate any permissions by hand. If you'd rather control how your roles are organized, [switch early](/guides/api/guides/custom-roles-and-permissions#migration-guide) and set them up yourself before the deadline. This automatic handling covers your **permission configuration** only. You must still update any integration that calls the deprecated `business_fields` endpoints or sends the `sidebar_pages` parameter, moving it to the Custom Roles endpoints and `permissions` model. **Manage the migration:** * Check your eligibility and status: [`GET /org/{org_id}/switch_to_custom_roles`](/api-reference/custom-roles/get-custom-roles-switch-status) * Switch early to organize roles yourself: [`POST /org/{org_id}/switch_to_custom_roles`](/api-reference/custom-roles/switch-to-custom-roles) * Full walkthrough: [Managing User Permissions with Custom Roles](/guides/api/guides/custom-roles-and-permissions) ⚠️ Takes effect 15th July 2026 ### Deprecation of business subscription endpoints **You are affected if:** * You are a provider The following endpoints are deprecated: * `GET /v2/business/{business_id}/subscription` * `POST /v2/business/{business_id}/subscribe` * `POST /v2/business/{business_id}/unsubscribe` Use these endpoints instead: * `GET /v2/business/{business_id}/plans` * `POST /v2/business/{business_id}/plans` # API Changelogs Source: https://developers.partoo.co/changelogs/api/changelogs These release notes list changes to Partoo. **📅 Deprecation Policy** Each major change (deprecated section) includes a 6-month grace period before it takes effect. * The date on the left shows when it was announced. * The date in the yellow box shows when it will take effect. 👉 You can find the full list of future API breaking changes on this [page](/changelogs/api/breaking-changes). ### Added #### Custom partner reviews You can now push into Partoo the reviews you collect on your own platform, and list the partners whose reviews are available to you. New endpoints: * [`POST /v2/reviews`](/api-reference/reviews/push-a-review-from-a-custom-partner) * [`DELETE /v2/reviews/{review_id}`](/api-reference/reviews/delete-a-review-pushed-by-a-custom-partner) * [`GET /v2/review-partners`](/api-reference/reviews/list-review-partners) Both write endpoints require an API key with `ORG_ADMIN` rights and the `review_edit` permission, on a partner enabled for your organization. `GET /v2/review-partners` returns those slugs, flagged with `is_custom: true`. #### Replies sent back to custom partners Replies written in Partoo on those reviews are sent back to you, so you can publish them on your own platform: * [`custom_reply_created`](/api-reference/webhooks-events/custom-review-reply-created) * [`custom_reply_updated`](/api-reference/webhooks-events/custom-review-reply-updated) * [`custom_reply_deleted`](/api-reference/webhooks-events/custom-review-reply-deleted) Their payload identifies the review with the `partner_slug` and `external_id` you pushed, never with Partoo ids. ### Changed #### Multiple webhook registrations per event type You can now register up to **5 webhooks per event type** per organization. All registered URLs receive the notification when an event fires. Previously, only one webhook URL per event type per `org_id` was allowed. The uniqueness constraint has been updated: you still cannot register the same URL twice for the same event type and `org_id`, but different URLs are now accepted. Affected endpoints: * `POST /v2/webhooks` * `PATCH /v2/webhooks/{webhook_id}` Attempting to create a webhook when 5 already exist for that event type returns a `400` error. ### Changed #### Read-only Google Lodging attributes Google Lodging attribute definitions can now indicate whether an attribute is read-only. Affected endpoints: * `GET /v2/lodging/list` * `POST /v2/business/{business_id}/lodging` `GET /v2/lodging/list` now returns a `read_only` boolean on each lodging attribute definition. When `read_only` is `true`, the attribute is provided for display purposes only and cannot be modified through the API. `POST /v2/business/{business_id}/lodging` rejects attempts to update read-only lodging attributes with a `400` error. API clients should use the `read_only` flag from the lodging definitions endpoint to hide, disable, or skip those attributes in update payloads. ### Added #### Google Lodging attributes endpoints You can now retrieve Google Lodging attribute definitions and manage lodging attribute values for businesses whose Google location can operate Lodging data. Affected endpoints: * `GET /v2/lodging/list` * `GET /v2/business/{business_id}/lodging` * `POST /v2/business/{business_id}/lodging` The business endpoints use the existing business id path parameter, including the `c-{code}` format for supported users. Updates are partial: only lodging attributes sent in the request body are changed. ⚠️ Takes effect 15th October 2026 ### Added #### New Diffusion Errors endpoint A new endpoint for retrieving diffusion errors grouped by publisher is now available. * [`POST /diffusion_errors/{business_id}`](/api-reference/presence/get-diffusion-errors-for-a-business) — Get diffusion errors for a business This endpoint provides improved error organization under the Diffusion domain and better feature control with proper authorization checks. **Note:** The old `POST /publisher_errors/{business_id}` endpoint is deprecated and will be removed on 15th October 2026. Please [migrate to the new endpoint](/changelogs/api/breaking-changes#deprecation-of-publisher_errors-endpoint). ### Added #### Custom headers for webhook configurations You can now define custom HTTP headers to be forwarded with every webhook request, when creating or updating a webhook. Affected endpoints: * `POST /v2/webhooks` * `PATCH /v2/webhooks/{webhook_id}` ### Added #### Branded dimension and filter for presence analytics keywords You can now distinguish between branded and discovery keywords in your Google Business Profile analytics. **New dimension:** * `branded` - Shows whether keywords are associated with your brand or are discovery keywords **New filter:** * `branded=true` - Returns only branded keywords (e.g., "Castorama", "Casto") * `branded=false` - Returns only discovery keywords (e.g., "bricolage", "magasin outillage") **Affected endpoints:** * `GET /v2/presence_analytics/keywords` **Example usage:** ```bash theme={null} # Get all keywords with branded dimension GET /v2/presence_analytics/keywords?dimensions=month,keyword,branded&metrics=count,threshold # Filter only branded keywords GET /v2/presence_analytics/keywords?dimensions=month,keyword,branded&branded=true&metrics=count,threshold # Filter only discovery keywords GET /v2/presence_analytics/keywords?dimensions=month,keyword,branded&branded=false&metrics=count,threshold ``` **Response format:** ```json theme={null} { "keywords": [ { "branded": "branded", "keyword": "foo", "count": 9001, "date": "2022-03-01", "bucket": "month" }, { "branded": "discovery", "keyword": "bar", "threshold": 42, "date": "2022-03-01", "bucket": "month" } ] } ``` This enhancement helps businesses analyze their brand visibility versus generic search performance in Google Business Profile. ⚠️ Takes effect 15th July 2026 ### Deprecated #### Business subscription management endpoints Update your integrations before 15th July 2026. See the [breaking change details](/changelogs/api/breaking-changes#deprecation-of-business-subscription-endpoints). You are affected if: * You are a provider The following endpoints are deprecated: * `GET /v2/business/{business_id}/subscription` * `POST /v2/business/{business_id}/subscribe` * `POST /v2/business/{business_id}/unsubscribe` Use these endpoints instead: * `GET /v2/business/{business_id}/plans` * `POST /v2/business/{business_id}/plans` ⚠️ Takes effect 15th July 2026 ### Deprecated Update your integrations to remove dependencies on these endpoints before 15th July 2026. See the [breaking change details](/changelogs/api/breaking-changes#deprecation-of-business-fields-endpoints-and-sidebar_pages). If you are currently using any of the below endpoints or parameters to limit sidebar visibility for users, please migrate to the new Custom Roles system before the specified deprecation date. #### Deprecated endpoints * [`GET /org/{org_id}/business_fields`](/api-reference/business-fields/business-fields-configuration-for-an-organization) — organization-level business fields (deprecated) * [`GET /business/{business_id}/business_fields`](/api-reference/business-fields/business-fields-configuration-for-a-business) — business-level business fields (deprecated) If you used `GET /org/{org_id}/business_fields` to retrieve the organization's list of custom fields, use [`GET /v2/custom_fields`](/api-reference/custom-fields/get-custom-fields) instead. #### Deprecated user parameters * `sidebar_pages` - deprecated in favor of the new Custom Roles and the `permissions` model. Seen in: * [`POST /v2/user`](/api-reference/users/create-user) (create user) * [`POST /v2/user/{user_id}`](/api-reference/users/update-user) (update user) ### Added #### New Custom Roles endpoints You can now manage Custom Roles for your organization using the following endpoints: * [`GET /v2/custom_role`](/api-reference/custom-roles/list-custom-roles) — List Custom Roles * [`POST /v2/custom_role`](/api-reference/custom-roles/create-custom-role) — Create Custom Role * [`GET /v2/custom_role/{custom_role_api_id}`](/api-reference/custom-roles/get-custom-role) — Get Custom Role detail * [`POST /v2/custom_role/{custom_role_api_id}`](/api-reference/custom-roles/update-custom-role) — Update Custom Role * [`DELETE /v2/custom_role/{custom_role_api_id}`](/api-reference/custom-roles/delete-custom-role) — Delete Custom Role * [`POST /v2/custom_role/duplicate`](/api-reference/custom-roles/duplicate-custom-role) — Duplicate an existing Custom Role * [`GET /v2/permissions`](/api-reference/custom-roles/get-permissions) — List available permissions (used when building custom role permissions) ### Updated Endpoints In addition, user endpoints now accept a `custom_role` parameter allowing assignment of a Custom Role by its `api_id`: * `custom_role` (string) - API identifier of the custom role to assign to a user. Seen in: * [`POST /v2/user`](/api-reference/users/create-user) (create user) * [`POST /v2/user/{user_id}`](/api-reference/users/update-user) (update user) ⚠️ Takes effect 15th January 2026 ### Deprecated #### `phone` and `keywords` fields for users Please note that as of **15th January 2026**, these fields will be removed. The `phone` and `keywords` fields in all user-related endpoints are now deprecated and will be permanently removed. #### Image message sending via direct upload Please note that as of **15th January 2026**, this change will be applied. Image messages can no longer be sent using direct file uploads (`form-data`) through: `POST /v2/messages` You are affected if: * You send messages via the message API on behalf of a business * You upload image messages via direct file upload Use public URLs to upload images instead. This change harmonizes how media is handled across the API. ### Added #### Support for custom channels in messaging You can now send **Text** messages through custom-defined channels via: `POST /v2/custom-channels/{channel_id}/messages` Impacted endpoints: * `GET /v2/conversations` * `GET /v2/conversations/{conversation_id}` * `EVENT message_created` * `EVENT message_updated` ### Added #### Media messaging support You can now send and receive: * **Audio** * **Video** * **Document** Not all channels support all media types. | Channel | Image | Video | Audio | Document | | - | :-: | :-: | :-: | :-: | | Facebook | ✅ | ✅ | ✅ | ✅ | | Instagram | ✅ | ✅ | ✅ | ❌ | | SMS | ❌ | ❌ | ❌ | ❌ | | WhatsApp | ✅ | ✅ | ✅ | ✅ | Affected endpoints: * `GET /v2/conversations` * `GET /v2/conversations/{conversation_id}` * `GET /v2/messages` * `POST /v2/messages` * `EVENT message_created` * `EVENT message_updated` ### Added #### Webhook configuration API You can now configure webhooks directly from the API or in **Settings > Integrations**. ### Changed #### Content-Type enforcement All `POST`, `PATCH`, and `PUT` requests now require a valid `Content-Type` header. Default: `application/json`. This is a breaking change following webserver upgrades. Review your client integrations. ### Removed #### `category_gmb_id` and presence analytics * `category_gmb_id` is removed. Use `category_gmb_name` instead. * Presence analytics endpoints are removed. Use **Profile metrics** and **Profile keywords** endpoints instead. ### Deprecated #### Review analytics V1 API The following endpoints are deprecated: * `GET /v2/reviews/stats` * `GET /v2/reviews/qualitative-evolution` * `GET /v2/reviews/quantitative-evolution` Use `GET /v2/review_analytics/metrics` instead. The properties `treated`, `not_treated`, and `answer_time` are no longer available. #### `products` in favor of `features` We are introducing a more granular feature-based permission system across organizations, businesses, and users. ### Changed #### Mappings for review analytics * `/v2/reviews/stats` → `?metrics=average_rating,rating_distribution,reply_time,reviews_count` * `/v2/reviews/quantitative-evolution` → `?dimensions={day|week|month|year}&metrics=reviews_count` * `/v2/reviews/qualitative-evolution` → `?dimensions={day|week|month|year}&metrics=reviews_count,average_rating` #### New `features` field usage ##### Organization * Use `org_features` to get the active features * Use `features` to list all available features ##### Business * New field: `features` * Searchable using `features__in` and `features__notin` ##### User * `sidebar_products` → `sidebar_pages` During the transition, updating `sidebar_products` may auto-assign features like `posts`, `bulk_modification`, `diffusion`, or `presence_analytics` depending on organizational access. #### Deprecated fields * `has_google_post` * `display_google_post` * `sidebar_products` ### Changed #### Content-Type validation enforced All `POST`, `PATCH`, and `PUT` requests must now specify a valid `Content-Type`. Requests without an appropriate `Content-Type` header may be rejected. ### Removed #### GmbServices and presence analytics * `category_gmb_id` fully removed from GmbServices * Deprecated presence analytics endpoints fully removed ### Added #### Store Code identification enabled Use business codes instead of IDs in endpoints. Example: ```bash theme={null} curl -H "x-APIKey: ${API_KEY}" --json '{"address_full": "221b Baker Street"}' \ https://api.partoo.co/v2/business/c-LON-HQ ``` Use the `/c-` prefix to denote a business code path. ### Removed #### `REPEATABLE_URL` no longer supported Replace with Place Action Links: * `GET /business/{business_id}/place_action_links` * `POST /business/{business_id}/place_action_links` ### Changed #### Nullable business address fields Fields like `address`, `address_full`, `zipcode`, `city`, `lat`, and `long` can return `null`. #### DELETE endpoint body parameters deprecated * `force` → query param for `DELETE /organization` * `forced_update` → `force` in `DELETE /custom-field` All deprecated DELETE body params will be removed by **15th January 2025**. #### `forced_update` renamed to `force` in PUT In `PUT /custom-field`, parameter `forced_update` is now `force`. ### Security #### Webhooks now signed Webhook requests are signed. See **Webhook Security** for verifying signatures. ### Fixed #### Swagger corrections 🎉 Updated Swagger documentation to OpenAPI 3.0 standards. No API changes were made—your current integrations continue to work. You can now use auto-generation tools more effectively. ### Added #### Publisher Errors Reporting Endpoint You can now report and view publisher-specific errors during business edits. This allows better diagnostics and corrections. ### Security #### Rate limiting enabled Limit: **300 requests per minute** per organization. Integrations exceeding limits may be throttled. ### Deprecated #### Presence analytics endpoints * `GET /v2/presence_analytics` * `GET /v2/presence_analytics/export` ### Removed #### Google Posts insights Google views and clicks data are no longer available. Facebook insights still available via `GET /v2/posts`. ### Added #### Messaging APIs released Support for: * Conversations * Messaging settings * Messages * Webhooks ### Removed #### Google Post endpoints removed Deprecated in favor of unified `/posts`. ### Changed #### `category_gmb_id` fields replaced With `category_gmb_name` in: * `GET /v2/services/suggestions` * `GET /v2/business/{business_id}/services` * `POST /v2/business/{business_id}/free_form_services` * `POST /v2/business/{business_id}/structured_services` ### Deprecated #### Categories endpoint * `GET /v2/category/{category_id}` → replaced by `GET /v2/categories/{category_id}` ### Changed #### Category enhancements * `with_names` for translated names * `with_countries` for available countries ### Removed #### Obsolete integration endpoints * `GET /v2/business/{business_id}/integration_status` * `GET /v2/business/{business_id}/partner_urls` * `GET /v2/publisher_states/business_info` * `GET /v2/publisher_states/businesses_info` Use: `GET /v2/publisher_states` #### `template_id` removed from review booster * Affects: `POST /v2/review_booster/send_invitation` Templates in use are not affected. ### Changed #### Unified search result ordering All search endpoints now support `order_by`. #### Address field cleanup `address_details` deprecated in favor of `address_full`. Do not use `address_full` and `address_details` together. ### Added #### Pagination support Use `per_page` in: * `GET /v2/reviews` * `GET /v2/business/search` * `GET /v2/user/search` ### Changed #### Sandbox API base URL New: `api.sandbox.partoo.co` Old: `sandbox.api.partoo.co` (deprecated) ### Deprecated #### Obsolete endpoints * `GET /v2/GET street types` * `GET /v2/GET number supplements` ### Changed #### Category endpoint updates * `id` is now an integer * `gmb_id` added to response ### Deprecated #### Old category ID format Use `gcid:climbing_gym` instead of legacy string IDs. Use `/v2/categories` to fetch valid categories. ### Removed #### Categories search endpoint Use: `GET /v2/categories` ### Deprecated #### API key authorization routes * `POST /v2/authorize` * `GET /v2/authorize/list` * `POST /v2/authorize/revoke` Use: `POST /v2/connection/generate_token` #### Business fields * `clean_name` * `video` * `siret` * `news` Field `country` now uses a standardized code format. # Breaking Changes Source: https://developers.partoo.co/changelogs/sdk/breaking-changes This page provides information about breaking changes to the SDK. **🟢 No Upcoming Breaking Changes** If you don’t see any **breaking changes** listed on this page, that’s **normal**.\ It simply means there are no upcoming **breaking changes** or required **updates** for the next few months. # SDK Changelogs Source: https://developers.partoo.co/changelogs/sdk/changelogs New updates and improvements **📅 Deprecation Policy** Each major change (deprecated section) includes a 6-month grace period before it takes effect. * The date on the left shows when it was announced. * The date in the yellow box shows when it will take effect. 👉 You can find the full list of SDK breaking changes on this [page](/changelogs/sdk/breaking-changes). ### Removed #### Removed obsolete SDK options Please note that as of **July 15, 2025**, these options will be removed. The following options were removed from the SDK configuration as they are no longer supported: * `displayUserParams` * `displayPartnerConnexionBanner` * `displayBusinessListSearch` * `displayMultibusinessSelection` * `displayBusinessAdmin` * `displayEditBusinessSelector` ### Changed #### JS file URL deprecation The previous SDK URLs for sandbox and production environments are deprecated: * `https://static.sandbox.partoo.co/javascript/build/partoo.js` * `https://static.partoo.co/javascript/build/partoo.js` See updated instructions in the [Getting started guide](https://developers.partoo.co/js_sdk/getting_started.html#step-1-import-js-sdk-in-your-html-page). ### Removed #### Removed route Please note that as of **April 15, 2025**, this route will be removed. * The `chatPreferences` route was removed from the navigation API. ### Added #### Added route * New route added to the navigation API: `chatPreferences` ### Added #### Added route * New route added to the navigation API: `whatsappSettings` ### Added #### Added route * New route added to the navigation API: `googleVerification` ### Added #### Enhanced filters * Added support for post status filters using a new `pageOptions.status` parameter. ### Changed #### Route update * Replaced the `"googlePosts"` route with `"posts"` in the `navigate` function. * `"googlePosts"` will remain supported until **15th November 2023**. ### Added #### Added route * New route added to the navigation API: `bulkUpdate` ### Added #### Review filtering * Added an optional `status` filter parameter when navigating to the `reviewManagement` page. ### Changed #### Init behavior improvements * You can now pre-load the business edit view by passing both `selectedBusinessId` and `startPage: "business"` during initialization. ### Added #### New SDK options Two new optional configuration fields were added: * `displayBusinessModalFilters`: Toggle the Business filter button in the UI. * `selectedBusinessId`: Select a specific business on init. ### Changed #### Authentication update Due to third-party cookie restrictions, the SDK now uses JWT tokens instead of session cookies to maintain user sessions. ### Added #### New callbacks Added support for the following callbacks: * `business_additional_info_updated` * `business_address_updated` * `business_contact_updated` * `business_description_updated` * `business_open_hours_updated` ### Added #### New callbacks * `pm_view_go_to_edit_click` * `pm_view_go_to_partner_connection_click` ### Added #### Feature addition * Added `startPageAnchorParam` to support anchor parameters in login URLs. ### Fixed #### Bug fixes * Fixed an issue where the `startPage` parameter was not working with `"business"`. # Errors Source: https://developers.partoo.co/guides/api/getting-started/api-fundamentals/errors ## Overview The Partoo API uses standard HTTP response codes to indicate success or failure. This guide covers the most common error codes and how to respond to them effectively. HTTP status codes are grouped into three categories: * **2xx**: Success * **4xx**: Client Errors * **5xx**: Server Errors The request is malformed or missing required fields. ```json theme={null} { "error": { "json": {} } } ``` No valid API key was provided. ```json theme={null} { "error": { "authentication": "User not authenticated" } } ``` The API key doesn't have permission to perform this request. ```json theme={null} { "error": { "authorization": "Operation not allowed" } } ``` The resource you're looking for doesn't exist. ```json theme={null} { "error": { "json": "Resource not found" } } ``` Ensure that the `Content-Type` header is set to `application/json` on POST, PUT, and PATCH requests. ```json theme={null} { "errors": { "json": "Unsupported media type. Please use application/json" } } ``` Your application has hit the rate limit. See Rate Limits for more information. # Overview Source: https://developers.partoo.co/guides/api/getting-started/api-fundamentals/index Core concepts and best practices for using the Partoo API securely and efficiently. Welcome to **API Fundamentals**. This section covers everything you need to know to build robust, secure, and well-behaved integrations with the Partoo API. Understand and troubleshoot common HTTP and JSON error responses. Learn how to work within API rate limits and handle 429 responses. Follow best practices for API key usage and avoid common security mistakes. Implement smart retry logic to recover from transient errors and rate limits. # Rate Limiting Source: https://developers.partoo.co/guides/api/getting-started/api-fundamentals/rate-limits Understand and manage API rate limits to ensure reliable access. ## Overview Partoo enforces rate limiting to ensure fair and stable use of the API across all users. By default, each organization is allowed **300 requests per minute**. ## Rate Limit Headers When rate limits are exceeded, the API returns: * HTTP status `429` * A `Retry-After` header specifying when to retry ```http theme={null} HTTP/1.1 429 Too Many Requests Retry-After: 60 ``` If your integration requires more calls for any reason, get in touch with your Customer Success Manager to update this limit, subject to review by our Technical team. ## Tips to Avoid Rate Limiting To minimize the chance of hitting rate limits: * Space out your API calls instead of batching large volumes. * Use caching to avoid redundant requests. * Implement exponential backoff with jitter for retries. For retry strategies, see our Retry Tips page. # Retry Tips Source: https://developers.partoo.co/guides/api/getting-started/api-fundamentals/retry-tips Ensure robust integrations with retry logic for rate limits and transient errors. ## When to Retry Implement retry logic for the following situations: * **429 Too Many Requests** * **5xx Server Errors** (e.g., 500, 503) Use exponential backoff with jitter to space retries safely and avoid system overload. Learn more about how rate limits work on our Rate Limiting page. ## Retry Headers For 429 errors, respect the `Retry-After` header value: ```http theme={null} Retry-After: 60 ``` Check if the HTTP status code equals 429. Use the value from the `Retry-After` header to delay your retry. Reattempt the same request after the delay. Avoid tight retry loops — they may cause cascading failures or get your integration rate-limited further. # Getting Started Source: https://developers.partoo.co/guides/api/getting-started/getting-started Learn how to obtain API keys, test safely in the Sandbox environment, and promote your integration to Production in Partoo. ## Overview Partoo provides two separate environments: * **Sandbox** – a safe space to build and test new integrations. * **Production** – the live environment where real data and customers are affected. Always begin in Sandbox, validate your workflow end-to-end, and then request Production access. Sandbox is empty by default and offers only a subset of features. Populate test data or use mocks as needed. #### Missing features in the Sandbox The Sandbox environment is designed for safe testing and does not support all production features. Notably disabled features include: * **Address geocoding** * Publishing to Google, Facebook, and other platforms * Importing Google or Facebook listings * Access to live reviews or analytics data You can manually populate your test environment with sample data.\ Contact your Account Manager to request additional sandbox capabilities. ## Prerequisites * A **Partoo Account Manager** assigned to your organisation * Network access to `*.partoo.co` domains ## Quick start Contact your Partoo Account Manager and ask for a **Sandbox API key**. Pass your Sandbox API key in every request header. All API calls that omit the `x-APIKey` header return **401 Unauthorized**. Test calling an endpoint to ensure your sandbox key works correctly. Use our interactive API Reference Docs to test endpoints individually with ease. ```bash cURL theme={null} curl --location 'https://api.sandbox.partoo.co/v2/business/search' \ --header 'x-APIKey: SANDBOX_API_KEY' ``` A **200 OK** response confirms that your key is valid and that the route is available to your user. If you need to inspect data or configure settings via the web app, ask your Account Manager to create a **Sandbox user** for you. UI access is not required for API-only integrations. Iterate until all test scenarios succeed in Sandbox. Remove test data and ensure idempotent behaviour. Keep environment variables such as `BASE_URL` and `API_KEY` separate so you can switch contexts without code changes. **Explore Partoo's capabilities** Before starting to build your integration, take time to understand the full scope of what Partoo offers: * [**API Fundamentals**](/guides/api/getting-started/api-fundamentals) – Learn how to use the Partoo API effectively and efficiently. * [**Structures**](/guides/api/getting-started/structures) – Learn how Partoo organizes data hierarchically (Organizations, Groups, Businesses) * [**Roles**](/guides/api/getting-started/roles) – Understand user permissions and access levels within the platform * **Use Cases** – Discover the many ways you can leverage Partoo's API for location management, review handling, messaging, and so on. Understanding these fundamentals will help you design a more robust integration that takes full advantage of Partoo's features. Once you're confident that your integration is production-ready, contact your Partoo Account Manager to request user access in Production and access to the API Key Manager tool. Within the Partoo Web Application, you can then generate and manage your own API Keys. To know more about generating and managing your own API Keys, please refer to the [API Keys Generation](/guides/api/resources/settings/security_and_api_key_usage) guide. ```bash cURL theme={null} curl --location 'https://api.partoo.co/v2/business/search' \ --header 'x-APIKey: SANDBOX_API_KEY' ``` Successful calls against the Production endpoint indicate that your integration is live. # User Roles and Permissions Source: https://developers.partoo.co/guides/api/getting-started/roles Understand how each Partoo role controls read and write access to API resources. A **role** defines what you can **read** and/or **write** for every resource (such as users, organizations, or businesses) and at which **scope** that access applies. **Custom Roles Available** In addition to the standard roles below, you can create custom roles with granular permissions tailored to your organization's needs. Learn more in our [Custom Roles and Permissions guide](/guides/api/guides/custom-roles-and-permissions). ## Quick Reference: Available Roles | Role | Intended for | High-level capabilities | Permissions customizable with [Custom Roles](/guides/api/guides/custom-roles-and-permissions)? | | - | - | - | - | | `ORG_ADMIN` | Client administrators | Manage users and businesses in **their** organization. | ❌ | | `ORG_MANAGER` | Client users requiring access to the full scope of the organization. | Manage users and businesses in **their** organization. | ✅ | | `GROUP_MANAGER` | Client group managers | Manage users and businesses inside their group. | ✅ | | `BUSINESS_MANAGER` | Client business managers | Manage businesses inside their group; limited user management. | ✅ | | `PUBLISHER` | External data consumers | **Read-only** access to businesses subscribed to Presence Management. | ❌ | The `ORG_MANAGER`, `GROUP_MANAGER`, and `BUSINESS_MANAGER` roles can be overwritten with built-in custom roles that provide different permissions. Learn how to configure these in our [Custom Roles and Permissions guide](/guides/api/guides/custom-roles-and-permissions). *** ## Detailed Permissions by Role All permissions listed below assume the user is not using a Custom Role that alters these defaults. For more information about custom roles, see [Managing User Permissions with Custom Roles](/guides/api/guides/custom-roles-and-permissions). **Users with the `ORG_ADMIN` or `PUBLISHER` role cannot be modified with custom roles.** `ORG_ADMIN` users always have full access to their organization, while `PUBLISHER` users always have read-only access to locations with an active Presence Management subscription. ### Read Access | Resource | Scope | Details | | - | - | - | | **User** | Organization | Read users in the same organization. | | **Organization** | Organization | Read your own organization object. | | **Group** | Organization | Read groups in the same organization. | | **Business** | Organization | Read businesses in the same organization. | ### Write Access | Resource | Scope | Allowed actions | | - | - | - | | **User** | Organization | • Create users (inherit provider & `org_id`)
• Update users in the organization
• Assign roles **`ORG_MANAGER`**, **`GROUP_MANAGER`**, or **`BUSINESS_MANAGER`** | | **Organization** | Organization | • Update the organization itself
• *Cannot* create new organizations | | **Group** | Organization | • Create groups (inherit provider & `org_id`)
• Update groups in the organization | | **Business** | Organization | • Create businesses (inherit provider & `org_id`)
• Update businesses in the organization |
### Read Access | Resource | Scope | Details | | - | - | - | | **User** | Organization | Read users in the same organization. | | **Organization** | Organization | Read your own organization object. | | **Group** | Organization | Read groups in the same organization. | | **Business** | Organization | Read businesses in the same organization. | ### Write Access | Resource | Scope | Allowed actions | | - | - | - | | **User** | Organization | • Create users (inherit provider & `org_id`)
• Update users in the organization
• Assign roles **`GROUP_MANAGER`** or **`BUSINESS_MANAGER`** | | **Organization** | Organization | *No write access* | | **Group** | Organization | • Create groups (inherit provider & `org_id`)
• Update groups in the organization | | **Business** | Organization | • Create businesses (inherit provider & `org_id`)
• Update businesses in the organization |
### Read Access | Resource | Scope | Details | | - | - | - | | **User** | Organization | Read users in the same organization. | | **Organization** | Organization | Read your own organization object. | | **Group** | Group | Read your own group. | | **Business** | Group | Read businesses in your group. | ### Write Access | Resource | Scope | Allowed actions | | - | - | - | | **Business** | Group | • Update businesses in your group
• *Cannot* create businesses | | **User** | Self | Update your own user profile | | *Others* | — | *No write access* |
### Read Access | Resource | Scope | Details | | - | - | - | | **User** | Organization | Read users in the same organization. | | **Organization** | Organization | Read your own organization object. | | **Group** | Group | Read your own group. | | **Business** | Business | Read businesses you have direct access to. | ### Write Access | Resource | Scope | Allowed actions | | - | - | - | | **Business** | Business | Update businesses you have direct access to. | | **User** | Self | Update your own user profile | | *Others* | — | *No write access* | > **Publisher** is a **read-only** role.\ > Publishers use Partoo solely as a data source for locations with an active Presence Management subscription. | Resource | Scope | Access | | - | - | - | | **Business** | Subscribed businesses | Read only | | *All others* | — | No access |
# Structure Source: https://developers.partoo.co/guides/api/getting-started/structures Explore the four key personas : Organization, User, Business, and Group to understand how they connect inside the Partoo ecosystem. These four personas form a strict hierarchy. Each child persona inherits the context of its parent, ensuring consistent and scalable resource management. ## Persona Overview | Persona | Parent | Children | Example | | - | - | - | - | | **Organization** | | Business, Group, User | *Sportitude*, a fictional company selling outdoor and sports gear | | **Group** | Organization | Business | *France*, a regional cluster of businesses | | **Business** | Organization | — | *Sportitude Annecy*, a store location in the French Alps | | **User** | Organization | — | *Charlie Explorer*, a user managing reviews and listings | ## 🏢 Organization – The Company Representation The **Organization** is the customer's company inside Partoo. It manages its listings, users, and groupings under one roof. **Example: Sportitude** *Sportitude* is a fictional company selling hiking boots, snowboards, and activewear throughout France. * **Children:** Users, Businesses, Groups *** ## 📍 Business – The Location A **Business** represents a single location managed on Partoo. It contains the essential data that gets pushed to Google, Apple Maps, and other platforms. **Example: Sportitude - Annecy** This location in Annecy specializes in mountain and winter sports gear, catering to hikers and skiers. * **Parent:** Sportitude (Organization) *** ## 🌍 Group – The Organizer **Groups** are used to cluster multiple businesses together. They help organize listings by region, brand, or campaign needs. **Example: France** The *France* group includes all Sportitude locations across the country, allowing Charlie to manage settings in bulk. * **Parent:** Sportitude (Organization) * **Contains:** Multiple businesses Use groups to bulk-edit business hours, attributes, or branding assets across several listings. *** ## 👤 User – The One Who Operates A **User** is a person (or system) that interacts with Partoo through the dashboard or API. Their access is defined by roles and permissions. **Example: Charlie Stick** *Charlie Stick* is the regional manager for Sportitude France. He edits listings, schedules campaigns, manages reviews and replies to messages. * **Parent:** Sportitude (Organization) See [**Roles & Permissions**](/guides/api/getting-started/roles) to learn which features each user role can access. *** ## 🧭 Relationship Diagram Here's how all the personas relate in the Partoo hierarchy: Relationship diagram of Partoo personas # Managing User Permissions with Custom Roles Source: https://developers.partoo.co/guides/api/guides/custom-roles-and-permissions Learn about Partoo's Custom Roles feature, how to use it in order to manage permissions, including migration notes from our previous system, and examples of REST API usage. ## What are Custom Roles? Partoo's Custom Roles feature enables organizations to create granular permission systems that go beyond traditional user roles. This powerful feature allows you to define precisely what features and data each user can access and modify within your organization. With Custom Roles, you can: * Create tailored user roles with specific permission sets * Control access to individual features and data fields * Assign roles to users through the Partoo app or REST API * Maintain fine-grained security and access control ### Quick Navigation * [Breaking Changes](#breaking-changes) - Breaking changes from the legacy system using "Business Fields" and "Sidebar Pages" * [Before Custom Roles](#before-custom-roles) - Legacy permission system overview * [Using Custom Roles](#using-the-new-custom-roles-feature) - New system overview * [Migration Guide](#migration-guide) - How to migrate your organization from the legacy system of permissions to the new Custom Role system * [REST API Examples](#rest-api-examples) - Practical implementation examples * [Best Practices](#best-practices) - Security and management recommendations * [Troubleshooting](#troubleshooting) - Common issues and solutions ## Breaking Changes For details on the deprecation of the legacy permission system, see the [Breaking Changes page](/changelogs/api/breaking-changes#deprecation-of-business-fields-endpoints-and-sidebar_pages). ## Before Custom Roles This section describes how things worked before the release of Custom Roles. ### Business Fields Before Custom Roles, "Business Field" permissions were limited and could only be configured for specific user roles: * **Business Manager** * **Group Manager** These permissions controlled which business data fields users could edit, for example: the "name" or "description" field of a business. **Inspection Endpoints:** * Organization-level: `GET /org/{org_id}/business_fields` * Business-level: `GET /business/{business_id}/business_fields` Business Fields Configuration ### Sidebar Pages **Sidebar Pages** represent feature-level permissions that control access to entire application sections. These permissions are broader than Business Fields and determine which features users can access. **Available Sidebar Pages:** * `DIFFUSION` * `BULK_MODIFICATION` * `POSTS` * `REVIEW_MANAGEMENT` * `REVIEW_INVITE` * `MESSAGES` * `PRESENCE_ANALYTICS` * `REVIEW_ANALYTICS` * `FEEDBACK_MANAGEMENT` If a user lacks access to a Sidebar Page (e.g., `REVIEW_MANAGEMENT`), they won't see the corresponding navigation link in the app sidebar, and cannot access that feature. **Inspection Endpoint:** `GET /user/{user_id}` User Edit Page - Sidebar Pages Selection ## Using the new Custom Roles feature This section describes how to use the new Custom Roles feature, in order to customize user permissions for your organization. Custom Roles give you a very fine level of control over user permissions, and because of this, we recommend you to initially use the GUI in the Partoo app to set up your new Custom Roles and permissions. The GUI offers you an easier way to visualize and manage the sometimes complex permission structures. ### Understanding Permissions Permissions are the building blocks of Custom Roles, identified by unique names like `business_edit` for editing business data. Permissions are what give a role its capabilities, and by combining different permissions, you can create roles that fit your organization's needs. Permissions can be anything from allowing you to edit the opening hours of businesses, to managing reviews or accessing analytics data. Permissions Overview
Permissions Detail **Permission Data Fields:** * **`name`**: Unique identifier for the permission (e.g., `review_reply_positive_reviews`) * **`disabled_for_roles`**: Array of user roles that cannot access this permission * **`depends_on`**: Specifies if this permission requires another permission to function * **Hierarchical Organization**: Permissions are grouped into logical `sections` and `subsections` for easier navigation **Retrieving Available Permissions:** Use the [GET `/permissions`](/api-reference/custom-roles/get-permissions) endpoint to discover all permissions available to your organization. **Example Response:** ```json theme={null} { "sections": [ { "name": "presence", "order": 100, "subsections": [ { "name": "presence_pages", "order": 100, "permissions": [ { "name": "business_edit", "order": 100, "feature": "business_edition", "depends_on": null, "disabled_for_roles": [] }, { "name": "business_edit_name", "order": 101, "feature": "business_edition", "depends_on": "business_edit", "disabled_for_roles": [] } ] } ] } ] } ``` ## Working with Custom Roles ### Custom Role Structure Every Custom Role consists of three essential components: * **`name`** — Human-readable display name for the role * **`api_id`** — Unique identifier used in API operations * ⚠️ This ID is used for retrieving, updating, and deleting roles. Changes can break integrations. * **`permissions`** — Array of permission identifiers granted by this role **Optional Fields:** * **`description`** — Detailed explanation of the role's purpose and scope The `api_id` field for custom roles is intended for use by integrations — changing it can break any existing integrations you have put in place. Use caution. ### Built-in Custom Roles Every organization has access to two pre-configured Custom Roles with special characteristics: **Restrictions on Built-in Roles:** * ✅ **Permissions**: Can be updated * ❌ **Name, API ID, Description**: Cannot be modified * ❌ **Deletion**: Cannot be deleted (use "reset" to restore defaults) **Identification:** Built-in roles are easily identified by these properties: * `is_builtin: true` * `org_id: null` **Updating a built-in role** To update a built-in role, use the [POST `/org/{org_id}/custom_role/{api_id}`](/api-reference/custom-roles/update-custom-role) endpoint with the desired permission changes, and the built-in role will be updated for your organization. The built-in role can now be identified by having the `build_in` property set to `true`, and `org_id` set to the ID of your organization. Built-in Custom Roles in App ### Assigning Custom Roles to Users To assign a Custom Role to a user, update the user's `custom_role` field with the desired role's `api_id`. Of course, you can also assign a Custom Role upon user creation. Once a user is assigned a Custom Role, they inherit all permissions defined in that role. If you create or update a user without a `custom_role`, users with the `GROUP_MANAGER` or `BUSINESS_MANAGER` role are automatically assigned the default built-in Custom Role associated with their role. **Endpoint:** [POST `/user/{user_id}`](/api-reference/users/update-user) and/or [POST `/user`](/api-reference/users/create-user) ### Role Lifecycle Management Custom Roles support full CRUD operations through the REST API: * **Create**: [POST `/org/{org_id}/custom_role`](/api-reference/custom-roles/create-custom-role) * **Read**: * [GET `/org/{org_id}/custom_role`](/api-reference/custom-roles/list-custom-roles) (list) * [GET `/org/{org_id}/custom_role/{api_id}`](/api-reference/custom-roles/get-custom-role) (single) * **Update**: [POST `/org/{org_id}/custom_role/{api_id}`](/api-reference/custom-roles/update-custom-role) * **Delete**: [DELETE `/org/{org_id}/custom_role/{api_id}`](/api-reference/custom-roles/delete-custom-role) * **Assigning Custom Roles to Users**: [POST `/user/{user_id}`](/api-reference/users/update-user) and/or [POST `/user`](/api-reference/users/create-user) ## Migration Guide This section covers the migration from the legacy Business Fields and Sidebar Pages system to Custom Roles. Organizations can check if they're eligible to migrate and manually trigger the switch when ready using the migration endpoints below. **Before making the switch, we strongly recommend reading this entire guide to understand the implications and changes that Custom Roles will bring to your organization.** The migration is **non-destructive** - all legacy permission data is preserved, allowing you to switch back to the legacy system if needed. However, after the deprecation period ends (6 months), legacy data will be permanently deleted and any organization that hasn't switched yet will be migrated to Custom Roles **automatically**. In that automatic migration, your Business Field permissions are applied to the built-in roles and, where users have specific Sidebar Pages, the matching Custom Roles are created for you — so no manual setup is required if you wait for the deadline. ### New Migration Endpoints To support the migration from the legacy permission system to Custom Roles, two new endpoints have been added: * **[GET `/org/{org_id}/switch_to_custom_roles`](/api-reference/custom-roles/get-custom-roles-switch-status)** - Get the current migration status for your organization. Returns information about whether your organization has switched to Custom Roles and whether you're allowed to make the switch. * **[POST `/org/{org_id}/switch_to_custom_roles`](/api-reference/custom-roles/switch-to-custom-roles)** - Update your organization's Custom Roles migration status. This endpoint allows you to enable or disable the Custom Roles feature for your organization (provided you have permission to make this change). These endpoints help you manage the transition from the legacy permission system to the new Custom Roles system at the organization level. ### Automatic Update of Built-in Roles When an organization switches to the Custom Roles system, the built-in roles (*Business Manager* and *Group Manager*) are automatically updated to match your current [Business Field permissions](#business-fields). This ensures that users assigned to these roles retain their existing capabilities without any manual intervention. This automatic update of the built-in roles happens when **you** switch early, and it applies to Business Field permissions only. [Sidebar Pages](#sidebar-pages) configurations are **not** migrated for you when you switch yourself — you're free to reorganize permissions however you like, recreating the equivalent Custom Roles through the Partoo app (or contact [api@partoo.fr](mailto:api@partoo.fr) for assistance). If you instead wait for the deadline, Partoo migrates everything automatically, including the Custom Roles needed for specific Sidebar Pages. For example, if you have restricted the *Business Manager* role from editing certain business fields, those restrictions will be reflected in the updated built-in Custom Role. ## REST API Examples Below are two concrete examples that demonstrate how to create custom roles with specific permission sets. ### Example A: Business Editor (restricted sensitive fields) In this example, we'll create a **"Business Editor"** role with comprehensive business editing permissions, while restricting access to sensitive fields. **Excluded Sensitive Fields:** * `business_edit_status` — Controls business open/closed status * `business_edit_siret` — French business tax identification number * `business_edit_code` — Business identifier used in integrations Call [GET `/permissions`](/api-reference/custom-roles/get-permissions) to retrieve all available permissions for your organization. Use [POST `/org/{org_id}/custom_role`](/api-reference/custom-roles/create-custom-role) with the selected permissions: ```json theme={null} { "name": "Business Editor", "api_id": "business_editor", "description": "Can edit most business data but cannot modify status, SIRET or store code.", "permissions": [ "business_edit", "business_edit_name", "business_edit_categories", "business_edit_country", "business_edit_city", "business_edit_zipcode", "business_edit_address", "business_edit_address2", "business_edit_coordinates", "business_edit_open_hours", "business_edit_specific_hours", "business_edit_more_hours", "business_edit_description_short", "business_edit_description_long", "business_edit_attributes", "business_edit_website_url", "business_edit_facebook_url", "business_edit_twitter_url", "business_edit_attributes_url", "business_edit_email", "business_edit_phone_number", "business_edit_fax", "business_edit_full_name", "business_edit_photo_secondary", "business_edit_photo_cover", "business_edit_photo_logo", "business_edit_services", "business_edit_menus" ] } ``` **Excluded Permissions**: `business_edit_status`, `business_edit_siret`, `business_edit_code` are intentionally omitted, preventing users from editing these sensitive fields. Once created, assign the "Business Editor" role to users by updating their `custom_role` field. **Endpoint**: [POST `/user/{user_id}`](/api-reference/users/update-user) **Request Body:** ```json theme={null} { "custom_role": "business_editor" } ``` ✅ **Result**: The user inherits all permissions defined in the "Business Editor" role. ### Example B: Review Manager (all review-related permissions) In this example, we'll create a comprehensive **"Review Manager"** role with full access to review-related functionality. **Role Capabilities:** * View and filter reviews * Download review data and analytics * Manage review states and flags * Create and assign tags * Reply to reviews (with templates and AI suggestions) * Access review booster features * Configure automated settings Use [GET `/permissions`](/api-reference/custom-roles/get-permissions) and select all `review_*` permissions for comprehensive coverage. Use [POST `/org/{org_id}/custom_role`](/api-reference/custom-roles/create-custom-role) to create the role: ```json theme={null} { "name": "Review Manager", "api_id": "review_manager", "description": "Full access to reviews, reply templates, tags, analytics and review booster features.", "permissions": [ "review_management", "review_download", "review_manage_state", "review_flag", "review_tags_manage", "review_tags_assign", "review_tags_manage_auto_settings", "review_reply_positive_reviews", "review_reply_neutral_reviews", "review_reply_negative_reviews", "review_reply_template_use", "review_reply_template_manage", "review_reply_suggestion", "review_manage_auto_reply_without_comments", "review_manage_auto_reply_with_comments", "review_analytics", "review_analytics_download", "review_analysis", "review_analysis_manage_settings", "review_booster", "review_booster_edit_expeditor_name", "review_booster_share_link", "review_booster_show_qr_code", "review_booster_manage_sms_template" ] } ``` **Scope Limitation**: This role grants comprehensive review access but no other permissions. Ensure you include all review-related permissions your users need. Assign the "Review Manager" role by updating the user's `custom_role` field. **Endpoint**: [POST `/user/{user_id}`](/api-reference/users/update-user) **Request Body:** ```json theme={null} { "custom_role": "review_manager" } ``` ✅ **Result**: The user gains comprehensive review management capabilities. ## Best Practices ### Role Design Principles * **Principle of Least Privilege**: Grant only the minimum permissions necessary for users to perform their tasks * **Role Naming**: Use clear, descriptive names that indicate the role's purpose and scope * **API ID Stability**: Choose stable `api_id` values that won't need changes * **Documentation**: Maintain clear descriptions for each custom role ## Troubleshooting ### Common Issues * **Permission Dependencies**: Ensure all required dependent permissions are included * **API ID Conflicts**: Choose unique `api_id` values within your organization * **Invalid Permissions**: Verify permissions exist using the permissions endpoint before assignment * **Built-in Role Modifications**: Remember that built-in roles have limited editability ### Getting Help If you encounter any issues with Custom Roles that are not covered in this guide or in the [Custom Roles API reference](/api-reference/custom-roles/list-custom-roles), please contact [api@partoo.fr](mailto:api@partoo.fr) for assistance. We kindly ask you to describe your issue in as much detail as possible, in order for us to provide you with the best support. # Display Data From Partoo Source: https://developers.partoo.co/guides/api/guides/display-data How to securely retrieve and render any Partoo data on a public website using a backend proxy with caching. ## Why Use a Backend Proxy? * **Hide your Partoo API key** from the browser. * **Cache responses** to improve performance and lower latency. * **Respect Partoo rate limits** by eliminating redundant calls. * **Centralize logging and error handling** in a single layer. If you already run an API gateway, add the proxy there to leverage its authentication, observability, and throttling features. ## Recommended Architecture For public-facing features—such as **Store Locator**, **Click & Collect**. Route all Partoo traffic through a caching proxy: ```mermaid theme={null} sequenceDiagram participant User as User Browser participant Frontend as Frontend App participant Proxy as Backend Proxy participant Cache as Cache DB participant Partoo as Partoo API User->>Frontend: Request location data Frontend->>Proxy: API request (no key exposed) Proxy->>Cache: Check for cached data alt Cache Hit Cache-->>Proxy: Return cached data Proxy-->>Frontend: Return cached data Frontend-->>User: Display results else Cache Miss Cache-->>Proxy: Cache miss Proxy->>Partoo: Request data with API key Partoo-->>Proxy: Return API response Proxy->>Cache: Store result in cache Proxy-->>Frontend: Return fresh data Frontend-->>User: Display results end ``` This architecture is not limited to websites. You can also apply it to **mobile applications** (iOS and Android). By caching API responses in your backend, you reduce load on the Partoo API and avoid hitting rate limits. See our Rate Limiting guide for details. ## Implementation Steps Expose an endpoint—e.g., `/api/partoo/data` in your server or serverless function. ```javascript Node.js (Express) theme={null} import express from 'express'; import fetch from 'node-fetch'; import cache from './cache.js'; // e.g. Redis const router = express.Router(); router.get('/data', async (req, res) => { const cacheKey = 'partoo:data'; const cached = await cache.get(cacheKey); if (cached) return res.json(JSON.parse(cached)); const response = await fetch('https://api.partoo.co/v2/business/search', { headers: { Authorization: `Bearer ${process.env.PARTOO_API_KEY}` } }); const data = await response.json(); await cache.set(cacheKey, JSON.stringify(data), { EX: 300 }); // 5 min res.json(data); }); export default router; ``` ```python FastAPI theme={null} import os, json, aiohttp, aioredis from fastapi import FastAPI, HTTPException app = FastAPI() redis = aioredis.from_url("redis://localhost") @app.get("/api/partoo/data") async def get_data(): cache_key = "partoo:data" if (cached := await redis.get(cache_key)): return json.loads(cached) async with aiohttp.ClientSession() as session: headers = {"Authorization": f"Bearer {os.getenv('PARTOO_API_KEY')}"} async with session.get("https://api.partoo.co/v2/business/search", headers=headers) as resp: if resp.status != 200: raise HTTPException(status_code=resp.status, detail=await resp.text()) data = await resp.json() await redis.set(cache_key, json.dumps(data), ex=300) return data ``` Never expose `PARTOO_API_KEY` in client-side code or version control. Select a cache store (Redis, Memcached, in-process LRU, or CDN-edge KV).\ Set a TTL that matches how often your Partoo data changes—**5 minutes** is a safe default. After deployment, confirm a second request is served from the cache by inspecting logs or cache metrics. Call the proxy instead of Partoo directly. ```javascript theme={null} async function fetchBusinesses() { const res = await fetch('/api/partoo/data'); if (!res.ok) throw new Error('Failed to load data'); return res.json(); } ``` Render the data using your preferred framework (**React, Vue, Svelte, etc...**). # Synchronize your Business to Partoo Source: https://developers.partoo.co/guides/api/guides/sync-business-to-partoo Learn how to synchronize your Business information from your internal system to Partoo using the API. This guide explains how to keep your Business information synchronized between your internal system and Partoo.\ You’ll learn how to update, create, and manage businesses through the Partoo API, and how to choose the right synchronization strategy. ## Prerequisites * You already store Business data (e.g., opening hours, addresses, names) in your internal system. * You have API access to Partoo with the appropriate credentials. * You are familiar with Partoo’s [Business Update](/api-reference/businesses/update-business) endpoint. For most integrations, **updating businesses** through the API is the core synchronization step. ## Identify the Business to Update To update a Business in Partoo through the [Business Update](/api-reference/businesses/update-business) endpoint, you must uniquely identify it. You can do this in two ways: * By `business_id` (immutable identifier generated by Partoo). * By `code` (a customizable identifier). Check the documentation of the [Business Update](/api-reference/businesses/update-business) endpoint for more details. ### Using `business_id` Best choice if you can store and maintain Partoo’s unique identifier. **Benefits** * Immutable, unique, and permanent. * Guarantees no synchronization issues. **Drawbacks** * Requires you to store the `business_id` in your system. * You must initially import and save existing `business_id`s. * When creating businesses via API, you must capture and store the new `business_id`. ### Using `code` (recommended) Best choice if you already have an internal identifier for businesses. **Benefits** * Flexible: you can assign your own internal ID to the `code` field. * Simplifies integration, since you don’t need to store Partoo’s `business_id`. **Drawbacks** * The `code` field can be modified by API or directly in Partoo, which may cause desynchronization. * Codes are sent to Google Business Profile (GBP). Changing them may lead to issues with existing GBP locations. Contact your Partoo account manager before changing codes. * Not supported when creating businesses at the **PROVIDER** level. ## Business Creation After setting up updates, about 80% of the work is done. Next, decide how to handle **new Business creations**: * **Low volume (\<10 per year):** Create businesses manually in Partoo, then let your automation update them. * **High volume:** Automate creation with the [Business Create](/api-reference/businesses/create-business) endpoint. If you're using the `business_id` method, then save the returned id into your database. ## Business Deletion Even though there is a [Business Delete](/api-reference/businesses/delete-business) endpoint, **deleting is not always the best option**. * **Recommended:** Set `status = closed` with the Business Update endpoint. This informs Google Business Profile and other platforms that your business is permanently closed. * **Optional:** Use the Delete endpoint later if you want to remove the business entirely from Partoo. Deleting a business does **not** set it as permanently closed in GBP. Use `status=closed` first. ## Partial vs Full Data Synchronization If your system doesn’t contain all business fields, you can still use a **hybrid approach**: * **Automated updates via API:** Key fields such as name, description, opening times. * **Manual updates in Partoo:** Optional fields that your local users manage. You can configure in Partoo which fields are editable by BUSINESS\_MANAGER and GROUP\_MANAGER roles. This allows you to control the key fields of your brand, while giving your users the possibility to fill the rest of the details that they master about your Business. ## Sync Frequency You control when synchronization happens. Two main strategies: 1. **Scheduled syncs** * Run every 6 hours, daily, or at another fixed interval. * Send only the Business data that was updated on your system since the last sync (if possible). * If not possible, you may sync all businesses, but be mindful of [rate limits](/guides/api/getting-started/api-fundamentals/rate-limits). 2. **Event-driven syncs (recommended)** * Trigger a sync immediately after data changes in your system. * Ensures Partoo always has the freshest data. ## Next Steps * Review the [Business Update](/api-reference/businesses/update-business) endpoint reference. * Decide whether you’ll use `business_id` or `code` as your identifier. * Map the fields from your system to the ones available on Partoo, and chose the ones to sync to Partoo. * Choose a sync frequency that balances performance and data freshness. * Test your workflow with a few businesses on Sandbox environment before moving to Prod. # User Provisioning with Partoo API Source: https://developers.partoo.co/guides/api/guides/user-management Learn how to integrate the Partoo User API to automatically manage user lifecycles create, update, and delete accounts based on your source-of-truth system. ## Overview A **user** is any individual who can sign in to your organization’s Partoo account.\ This guide explains how to configure the **Partoo User API** so every change in your source-of-truth database; new hires 👋, role changes 🔄, or departures 🚪 automatically syncs to Partoo. ## Prerequisites * **Partoo API key** with permission to manage users. * **User data** prepared in your system (email, role, group/business assignments). * Familiarity with the [Partoo User API reference](/guides/api/resources/user/user) — Create, Update, Delete endpoints. ## Define your integration scope The right approach depends on your company size and employee turnover: * **High-change environments**\ Automate the full lifecycle: create, update, and delete. This ensures permissions are always up to date. * **Low-change environments**\ Automate only critical routes (e.g., create and delete) and handle rare updates manually. There is no mandatory minimum: implement the full set or just a subset.\ The choice depends on your organization’s risk tolerance and operational overhead. ## User lifecycle Here is the user lifecycle we expect: | Stage | Trigger | Action | API Route | | - | - | - | - | | 👋 **Joiner** | New hire appears in HR/IdP system | Provision account | [`POST /user`](/api-reference/users/create-user) | | 🔄 **Mover** | Role, team, or scope change | Update permissions | [`POST /user/{user_id}`](/api-reference/users/update-user) | | 🚪 **Leaver** | Departure or access no longer required | Revoke access | [`DELETE /user/{user_id}`](/api-reference/users/delete-user) | Automated calls keep Partoo perfectly aligned with your source-of-truth at every step. ## Joiner, Mover, Leaver — API specification This section consolidates all requirements for **create**, **update**, and **delete** routes in a single reference. ### 1. Create — `POST /users` (Joiner) #### Define access You can **skip this section** if every user in your organization is an `ORG_ADMIN`.\ Admins automatically receive full access to all features, establishments, and groups.\ The details that follow apply **only** to `GROUP_MANAGER` (GM) and `BUSINESS_MANAGER` (BM) roles. * `GROUP_MANAGER` → populate the `accesses` array with the **IDs of groups** they must have. Example: ```json theme={null} "accesses": [ ["1", "2"], // businesses present in BOTH group 1 AND group 2 ["3"] // PLUS every business from group 3 ] ``` * `BUSINESS_MANAGER` → populate the `business_ids` array with **the IDs of the businesses** they oversee. Example: ```json theme={null} "business_ids": ["5409c35a97bbc544d8e26737", "5409c35a97bbc544d8e26738"] ``` #### Password setup and user status. * Omit `password` * Set `send_invitation: true` Result : status **invited** → email sent to create a password → becomes **active** after password setup * Provide a password (e.g., `"TempPwd#2025"`) * Omit `send_invitation` Result : status **active** immediately * Set `status: "invited"` * Omit password and `send_invitation` * Call [**Invite User**](/api-reference/users/invite-user) endpoint later #### SSO-only users Use when your organization already has Single Sign-On (SSO) configured: * Send `sso_only: true` in payload * Login flow: 1. User clicks **Sign in with your enterprise** 2. Enters email 3. Redirects to your Identity Provider (IdP) 4. No Partoo password accepted If the user attempts SSO before their Partoo record exists, login fails. Provision the user first. ### 2. Update — `POST /users/{user_id}` (Mover & Joiner corrections) Use to adjust roles, group/business scope, sidebar visibility, or to toggle `sso_only`. Every account has two identifiers: * `email` (mutable) * `user_id` (immutable, required for update/delete) Options to obtain `user_id`: 1. **Store it** at creation time. 2. **Lookup** later via `GET /user/search`. * Supports exact or fuzzy match. * URL-encode special characters in the query string (e.g., `+` → `%2B`). A successful update returns the full user object with refreshed permissions in real time. ### 3. Delete — `DELETE /users/{user_id}` (Leaver) * Permanently removes the user record. * Possibility to just disable the user, via the update route with `"disabled":"true"` Deletion is irreversible. To reinstate access, create a brand-new user. ## End-to-End account activation flow The diagram below visualizes the complete journey from employee creation in your source-of-truth to account activation (including mover and leaver events). ### 👋 Joiner — Create
```mermaid theme={null} flowchart TB %% ───────────── %% STYLE %% ───────────── classDef joiner fill:#E8FEE8,stroke:#2ECC40,stroke-width:2px,color:#064F1C; classDef system fill:#F4F4F4,stroke:#979797,stroke-dasharray:4 2,color:#333; %% ───────────── %% NODES %% ───────────── A["🗄️ Source-of-truth
(new hire)"]:::system B["POST /users
"]:::joiner C{"Sending
an invitation ?"}:::joiner D["📧 User receives invite"]:::joiner E["🔑 User sets password"]:::joiner F["✅ Account status: active"]:::joiner G["You set password "]:::joiner H["You set
send_invite:true "]:::joiner %% ───────────── %% EDGES %% ───────────── A --> B B --> C C -- "Yes" --> H --> D --> E --> F C -- "No" --> G --> F ```
### 🔄 Mover — Update ```mermaid theme={null} flowchart LR %% ───────────── %% STYLE %% ───────────── classDef mover fill:#E8F5FE,stroke:#1E90FF,stroke-width:2px,color:#0B3A63; classDef system fill:#F4F4F4,stroke:#979797,stroke-dasharray:4 2,color:#333; %% ───────────── %% NODES %% ───────────── G["🗄️ Source-of-truth
(role/team change)"]:::system H["POST /users/{user_id}"]:::mover I["⚡ Permissions updated"]:::mover %% ───────────── %% EDGES %% ───────────── G --> H --> I ``` ### 🚪 Leaver — Delete ```mermaid theme={null} flowchart LR %% ───────────── %% STYLE %% ───────────── classDef leaver fill:#FFEDEE,stroke:#FF4136,stroke-width:2px,color:#66060B; classDef system fill:#F4F4F4,stroke:#979797,stroke-dasharray:4 2,color:#333; %% ───────────── %% NODES %% ───────────── J["🗄️ Source-of-truth
(departure)"]:::system K["DELETE /users/{user_id}"]:::leaver L["🚫 Access revoked"]:::leaver A["POST /users/{user_id}"]:::leaver %% ───────────── %% EDGES %% ───────────── J --> K --> L J --> A -- disabled:true --> L ``` ## Next steps * Decide if you’ll automate **create → update → delete** or a subset * Choose a strategy for handling `user_id` (store vs. lookup) * Validate your integration in the **Sandbox environment** # Categories Source: https://developers.partoo.co/guides/api/resources/businesses/categories Learn how to effectively use and manage business categories to improve your local search visibility and connect with customers. Categories are essential identifiers that describe your business and help customers find you when searching for specific services. They play a crucial role in local search rankings and determine which attributes, services, menus, and place action links are available for your business listings. Categories are one of the key factors that affect your business's local ranking on Google and other directories. Choose them carefully to maximize your visibility. ## Understanding Categories ### What Are Business Categories? Business categories are standardized labels that describe what your business does. They help search engines and directory platforms understand your business type and connect you with relevant customer searches. Screenshot showing the display of the main business category on a Google Business Profile listing ### Why Categories Matter * **Local search ranking**: Categories directly influence how well your business ranks in local search results * **Data availability**: Your selected categories determine which Google Business Profile attributes, services, menus, and place action links you can use * **Customer discovery**: Well-chosen categories help customers find your business when searching for specific services ## Category Standards ### Google Business Profile as the Source Partoo uses Google Business Profile as the single source of truth for categories. This approach ensures: * **Relevance**: Google leverages search data to build the most comprehensive category catalog * **Completeness**: If a category exists on Google Business Profile, it's available in Partoo ### Automatic Synchronization Our category catalog stays current through daily synchronization with Google Business Profile: * **New categories**: Automatically added when Google creates them * **Removed categories**: Marked as obsolete when Google removes them * **Updated names**: Category names are updated to match Google's changes ## Category Selection Best Practices ### Recommended Approach Your primary category (first in the list) is the most important. Select the most specific category that accurately describes your core business. Note that your choice of primary category will also affect what *Attributes*, *Services*, *Menu options*, and *Place Action Links* are available for your business. These are additional details that help customers learn more about your business, such as `Wi-Fi available` or `Outdoor seating` for attributes, specific services you offer, the possibility to add a food menu, or actionable links like `Order Online`. The reason for this is that for certain categories, certain options are more relevant than others. For example, a `Coffee Shop` might have attributes related to seating options and the possibility of adding a menu, while a `Plumber` would have attributes related to service areas and specific services offered. When you select a specific category like "Pizza Restaurant," your business will also appear in searches for broader related categories like "Restaurant." Include up to 10 categories total, but focus on quality over quantity. Each additional category should represent a genuine service or product you offer. Order matters for your additional categories since different platforms have varying limits - some only use your first 3-4 categories. List your most important additional categories first to ensure they're included across all platforms. Adding irrelevant categories can hurt your local SEO performance. For each category, ask yourself: "If customers search for this category and find my business, will they click?" If the answer is no, don't use that category. ### Category Limits by Platform While Google accepts up to 10 categories, other platforms have different limits: * **Google Business Profile**: Up to 10 categories * **Facebook**: First 4 categories only * **Hoodspot**: First 3 categories only * **Apple**: Primary category only * **Le118000**: Primary category only We recommend defining at least 5 relevant categories to maximize visibility while maintaining quality. ## Category Mapping ### Publisher-Specific Mappings Each publisher platform has its own category system. We maintain mappings between Google Business Profile categories and equivalent categories on other platforms. ### Missing Mappings Occasionally, new categories may not have mappings for all publishers. We continuously monitor for these gaps and work to establish appropriate mappings as quickly as possible. ## Updating Categories for Your Businesses You can easily manage your business categories through the Partoo web application. The interface provides suggestions and allows you to add multiple categories to optimize your local search visibility. ### Accessing the Categories Section From your dashboard, select the business you want to update categories for. You'll see the Business Edit page where you can update your business data, including categories. Business dashboard showing category section In the "Describe your activity" section, you'll see the Categories option. This section shows your current primary category and allows you to add additional categories. The green checkmark indicates that you have at least one category configured for your business. ### Adding and Managing Categories Choose the main category that best describes your business from the dropdown menu. This will be your most important category for search rankings. The Categories page showing primary category selection In the "Additional categories" field, you can search for and add additional categories that represent other services or aspects of your business. The Categories page with suggested additional categories based on the primary category The interface provides intelligent suggestions to help you find relevant additional categories. These suggestions come from analyzing category combinations across all businesses on the Partoo platform. For example, *Pizza restaurant* businesses commonly also use *Pizza delivery*, *Pizza takeaway*, and *Italian restaurant*. As you add categories, they appear as tags that you can easily remove by clicking the "×" button if needed. The interface shows a counter (e.g., "8/9") indicating how many categories you've selected out of the maximum allowed. The Categories page showing selected primary and additional categories Remember that quality is more important than quantity. Choose only categories that genuinely represent your business offerings. After selecting your categories, save your changes to update your business profile across all connected platforms. ### Using the REST API to Manage Categories You can programmatically manage business categories through our REST API. The following endpoints provide complete category management functionality: #### Category Discovery Endpoints | Method | Name | Endpoint | Description | | - | - | - | - | | `GET` | List categories | **[/api/v2/categories](/api-reference/categories/list-partoo-categories)** | List and filter through all available Partoo categories | | `GET` | Get category | **[/api/v2/categories/\{category\_id}](/api-reference/categories/category-information)** | Retrieve detailed information about a specific category | | `GET` | Get suggested categories | **[/api/v2/categories/\{category\_id}/suggested](/api-reference/categories/suggested-additional-categories)** | Get recommended additional categories based on an existing category | #### Business Management Endpoints | Method | Name | Endpoint | Description | | - | - | - | - | | `POST` | Create business | **[/api/v2/businesses](/api-reference/businesses/create-business)** | Create a new business with categories | | `POST` | Update business | **[/api/v2/businesses/\{business\_id}](/api-reference/businesses/update-business)** | Update an existing business, including its categories | #### Complete Workflow Example Here is how you can use these endpoints together to implement a complete category management workflow: Start by retrieving the available categories to present options to your users: ```http theme={null} GET /api/v2/categories?search=restaurant&limit=20 ``` This helps users find relevant categories by searching or browsing the complete catalog. Once a user selects a primary category, get intelligent suggestions for additional categories: ```http theme={null} GET /api/v2/categories/{primary_category_id}/suggested ``` These suggestions are based on the most commonly used additional categories by businesses with the same primary category. Apply the selected categories to a business using either endpoint: **For new businesses:** ```json theme={null} POST /api/v2/businesses { "name": "My Pizza Place", "categories": [ # The first category of the array is always the primary category "gcid:pizza_restaurant", # Additional categories "gcid:italian_restaurant", "gcid:pizza_delivery_service" ], // ... other business data } ``` **For existing businesses:** ```json theme={null} POST /api/v2/businesses/{business_id} { "categories": [ "gcid:pizza_restaurant", "gcid:italian_restaurant", "gcid:pizza_delivery_service", "gcid:pizza_takeout_service" ] } ``` The first category in the array is treated as the primary category, which determines available attributes, services, menus, and place action links, and has the strongest impact on search rankings. Additional categories are treated as additional categories. Use the suggestions endpoint to provide the same intelligent category recommendations in your application that users experience in the Partoo web interface. ## Frequently Asked Questions No, we do not accept requests to add custom categories to our catalog. This is to ensure data quality and to prevent the use of invalid categories that could harm your business's search performance. We recommend 5-10 relevant categories. Your primary category is most important, followed by additional categories that accurately represent additional services or products you offer. Adding irrelevant categories can hurt your local SEO performance. Google Business Profile's category directory is comprehensive and should contain relevant options for any business type. Try searching for broader terms or synonyms if specific terms don't yield results. Your primary category determines which Google Business Profile attributes, services, menus, and place action links are available. Consider if a different primary category would unlock the needed data options for your business. No, different publishers have varying category limits and systems. While Google accepts up to 10 categories, other platforms may only use your primary category or the first few categories from your list. We continuously monitor for category changes from Google Business Profile. Here's what happens when Google removes a category: **Immediate Impact:** * The category is automatically marked as obsolete in our system * Updates to your Google Business Profile listing may temporarily fail **Our Response:** * Our team actively works to identify the most appropriate alternative category * We assign the replacement category to restore full functionality as quickly as possible * The obsolete category is replaced with the new one for all affected businesses still using the old, obsolete category We apologize for any inconvenience this may cause. The obsoletion of categories is caused by changes outside of our control, as we strive to always maintain accurate and effective category mappings. *** Need help with category selection or experiencing issues? Contact our support team for personalized assistance with optimizing your business categories. # Coordinates Source: https://developers.partoo.co/guides/api/resources/businesses/coordinates Learn how GPS coordinates work for businesses in the Partoo API and how they're handled across different platforms. ## Overview GPS coordinates in Partoo are critical for accurate business location representation across platforms like *Google Business Profile*, *Apple Maps*, and other location services. Understanding how coordinates are handled helps ensure proper location data management. ## Coordinate Fields Business coordinates are managed through two main fields in the API: | Field | Type | Description | | - | - | - | | `lat` | `number` \| `null` | Latitude coordinate (decimal degrees) | | `long` | `number` \| `null` | Longitude coordinate (decimal degrees) | Decimal coordinates should use dots (.) as separators, not commas. Example: `47.870341`, not `47,870341`. ## Coordinate Behavior The way coordinates are handled depends on how the business is created and whether GPS data is provided: ### When GPS Coordinates Are Provided If you provide GPS coordinates when: * Creating a business * Updating an existing business **Result**: The provided coordinates are: * ✅ Stored in Partoo's database * ✅ Sent to *Google Business Profile* * ✅ Returned via API responses ### When GPS Coordinates Are Not Provided If you don't provide GPS coordinates via the API: **Result**: * ❌ No coordinate data is sent from Partoo to *Google Business Profile* * ✅ *Google Business Profile* automatically generate coordinates based on the business address, which we save for each business * ✅ Auto-generated coordinates are returned in API responses * ⚠️ Auto-generated coordinates may not be perfectly accurate Auto-generated coordinates are computed based on the business address. While generally accurate, they may not represent the exact entrance or specific location within a building. ## Updating the Coordinates in the App You can also update business coordinates directly in the Partoo app. Navigate to the business page for the business you want to update, and click on your business address, which in turn opens a form where you can edit your address, as well as your GPS coordinates. Editing business coordinates in the Partoo app To update the coordinates on this page, simple drag and drop the map pin to the correct location, and save your changes. Editing business coordinates in the Partoo app ## REST API Examples ### Creating a Business with Coordinates When creating a business, include the `lat` and `long` fields: ```bash cURL theme={null} curl -X POST 'https://api.partoo.co/v2/business' \ -H 'x-APIKey: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "name": "Downtown Coffee Shop", "address_full": "123 Main Street, Springfield, IL", "city": "Springfield", "zipcode": "62701", "country": "US", "lat": 39.7817, "long": -89.6501, "categories": ["gcid:coffee_shop"] }' ``` ```python Python theme={null} import requests response = requests.post( 'https://api.partoo.co/v2/business', headers={ 'x-APIKey': 'YOUR_API_KEY', 'Content-Type': 'application/json' }, json={ 'name': 'Downtown Coffee Shop', 'address_full': '123 Main Street, Springfield, IL', 'city': 'Springfield', 'zipcode': '62701', 'country': 'US', 'lat': 39.7817, 'long': -89.6501, 'categories': ['gcid:coffee_shop'] } ) ``` ```javascript Node.js theme={null} const response = await fetch("https://api.partoo.co/v2/business", { method: "POST", headers: { "x-APIKey": "YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ name: "Downtown Coffee Shop", address_full: "123 Main Street, Springfield, IL", city: "Springfield", zipcode: "62701", country: "US", lat: 39.7817, long: -89.6501, categories: ["gcid:coffee_shop"], }), }); ``` ### Updating Business Coordinates You can update coordinates for an existing business: ```bash cURL theme={null} curl -X POST 'https://api.partoo.co/v2/business/5409c35a97bbc544d8e26737' \ -H 'x-APIKey: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "lat": 39.7825, "long": -89.6495 }' ``` ```python Python theme={null} import requests response = requests.post( 'https://api.partoo.co/v2/business/5409c35a97bbc544d8e26737', headers={ 'x-APIKey': 'YOUR_API_KEY', 'Content-Type': 'application/json' }, json={ 'lat': 39.7825, 'long': -89.6495 } ) ``` ```javascript Node.js theme={null} const response = await fetch( "https://api.partoo.co/v2/business/5409c35a97bbc544d8e26737", { method: "POST", headers: { "x-APIKey": "YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ lat: 39.7825, long: -89.6495, }), } ); ``` ### Retrieving Business Coordinates When fetching business information, coordinates are included in the response: ```bash cURL theme={null} curl -X GET 'https://api.partoo.co/v2/business/5409c35a97bbc544d8e26737' \ -H 'x-APIKey: YOUR_API_KEY' ``` ```python Python theme={null} import requests response = requests.get( 'https://api.partoo.co/v2/business/5409c35a97bbc544d8e26737', headers={'x-APIKey': 'YOUR_API_KEY'} ) data = response.json() latitude = data.get('lat') longitude = data.get('long') ``` ```javascript Node.js theme={null} const response = await fetch( "https://api.partoo.co/v2/business/5409c35a97bbc544d8e26737", { headers: { "x-APIKey": "YOUR_API_KEY", }, } ); const data = await response.json(); const latitude = data.lat; const longitude = data.long; ``` **Response structure:** ```json theme={null} { "id": "5409c35a97bbc544d8e26737", "name": "Downtown Coffee Shop", "address_full": "123 Main Street, Springfield, IL", "city": "Springfield", "lat": 39.7817, "long": -89.6501 // ... other business fields } ``` ## Related Endpoints * [Create Business](/api-reference/businesses/create-business) (`POST /v2/business`) * [Update Business](/api-reference/businesses/update-business) (`POST /v2/business/{business_id}`) * [Get Business](/api-reference/businesses/business-information) (`GET /v2/business/{business_id}`) # Custom Fields Source: https://developers.partoo.co/guides/api/resources/businesses/custom-fields Add and configure your own custom data fields. Custom Fields allow you to extend your businesses with additional data beyond the standard Partoo fields. They are organization-specific, fully configurable, and can be tailored to meet your company's unique business requirements. ## What are Custom Fields? Custom Fields are configurable fields that can be defined in addition to the standard business fields provided by Partoo. They are unique to your organization and can be adapted to suit your company's specific needs. They provide a flexible way to save custom data related to your businesses, storing any additional information that's important to your organization beyond the default available business data fields. You can create, update, and retrieve this data through the main App UI as well as our REST API for seamless integration with your existing systems and workflows. Custom Fields support a variety of data types. They integrate seamlessly with the business management interface, appearing in the Business Edit view based on their configured order. They are also included in REST API responses when retrieving business details. ### Use Cases Data saved in Custom Fields is never sent to any third parties such as Google, Meta, or Apple. Custom Fields are intended for your internal use only, providing a flexible way to store and manage extra information about your businesses. Custom Fields can be used for any purpose, here are some common use cases: * **Data Storage**: Store extra business attributes that are important to your organization but not covered by standard fields. Examples include store manager names, special amenities, or operational details. * **Integrations**: Send and receive Custom Field data using our REST API to support any sytems you use in your organization, such as store locators, inventory systems, CRM systems, etc. * **Any other data-related use case**: Anything else you can think of! There is no fixed purpose for Custom Fields beyond providing a flexible way to store and retrieve additional business data. In the end, you decide what data to store in Custom Fields and how to use it within your organization. ### Supported Field Types | Type | Description | Available Constraints | Additional Required Fields | | - | - | - | - | | `BOOLEAN` | True/false values | None | | | `TEXT` | Text strings | Optional max length | | | `INTEGER` | Whole numbers | Optional min/max values | | | `FLOAT` | Decimal numbers | Optional min/max values | | | `SINGLE_SELECT` | Single choice from predefined options | Optional `max_selected_values` | Requires `possible_values` array | | `MULTIPLE_SELECT` | Multiple choices from predefined options | Optional `max_selected_values` | Requires `possible_values` array | | `MULTIPLE_SELECT_IMAGE` | Multiple image choices with labels | Optional `max_selected_values` | Requires `possible_values`, `possible_images_urls`, and `possible_images_labels` arrays | | `IMAGES_UPLOADER` | Image upload with text fields | Configurable text fields with max lengths | | ### Field-Specific Configuration #### Selection Fields with Option IDs For select field types (`SINGLE_SELECT`, `MULTIPLE_SELECT`, and `MULTIPLE_SELECT_IMAGE`), the system automatically manages option identifiers: * **`possible_ids`**: An array of unique identifiers corresponding to each option in `possible_values` * **Automatic Management**: IDs are automatically created when adding new options and deleted when removing options * **Read-Only**: These IDs cannot be manually modified - they're managed automatically by the system The `possible_ids` field works alongside `possible_values` to provide stable references to select options, ensuring data consistency even when option labels change. #### Option Ordering For select field types (`SINGLE_SELECT`, `MULTIPLE_SELECT`, and `MULTIPLE_SELECT_IMAGE`), you can control the display order of options: * **`possible_orders`**: Optional array of integers specifying the display order of each option in `possible_values` * **Flexible ordering**: Each integer corresponds to the position preference for the option at the same index * **Example**: `[3, 1, 2]` would display the second option first, third option second, and first option third * **Order normalization**: Orders with "holes" are automatically simplified - for example, `[5, 8, 1]` will be returned as `[2, 3, 1]` When creating or editing fields with custom ordering, ensure the `possible_orders` array has the same length as `possible_values`, or leave it as `null` to use default ordering. #### Selection Constraints For select field types, you can limit the number of selections: * **`max_selected_values`**: Optional constraint limiting how many options can be selected * **Applies to**: `SINGLE_SELECT`, `MULTIPLE_SELECT`, and `MULTIPLE_SELECT_IMAGE` field types * **Default behavior**: No limit (users can select all available options for multiple select fields) * **Business validation**: When editing businesses, users cannot select more options than the configured maximum ### Sections and Organization Custom Fields can be organized into sections to group related fields together. Sections have: * **Name**: Unique identifier for the section * **Slug**: Optional unique identifier for the section * **Order**: Display position in the interface Fields within sections also have individual ordering for precise layout control. ## Managing Custom Fields through the App UI The Partoo app provides an intuitive interface for managing your organization's custom fields. You can access custom fields management by navigating to **Settings > Integrations > Custom fields**. ### Accessing Custom Fields Navigate to the custom fields management page through the main settings: 1. Go to **Settings** in the app sidebar 2. Select **Integrations** from the settings menu 3. Click on **Custom fields** Custom Fields Page showing 3 existing custom fields organized using one section. The custom fields page displays all your existing custom fields organized by sections. Each field shows its type, description, and current configuration. In the screenshot above, you can see fields like "Catering" (Yes/No type), "Delivery Options" (Select multiple), and "Manager" (Text type). ### Creating Custom Field Sections Before creating individual fields, you can organize them into logical sections. Sections help group related fields together for better organization and user experience. Sections are optional, you can create fields without assigning them to sections. Click the **Create** button and select the option to create a new section: Dialog for creating a new custom field section When creating a section, you'll need to provide: * **Section name**: A descriptive title for the group of fields (e.g., "This is my new Custom Field Section") * **Description** (optional): Details to explain the section's purpose (e.g., "Descriptions help a lot with keeping track of things!") * **Slug** (optional): Unique identifier for the section (e.g., "new\_section") The section will be created and available for organizing your custom fields. ### Creating Custom Fields Custom field type selection interface showing Yes/No, Number, Text, Select, Select Image, and Images uploader options From the custom fields page, click the **Create** button to add a new custom field: Dialog for creating a new custom field with configuration options When creating a custom field, configure the following: * **Name**: The display name for the field (e.g., "My new Custom Field") * **Description** (optional): Help text to explain the field's purpose * **Add to a section** (optional): Choose an existing section to organize the field (e.g., "Services") * **Field type**: Select from available types (Text, Yes/No, Select options, etc.) The field type determines what kind of data can be stored and how users will interact with it in the business editing interface. * **Slug** (optional): Unique identifier for the field (e.g., "my\_new\_custom\_field") * **Any type-specific constraints** (optional): Depending on the selected field type, you may need to configure additional options such as possible values for select fields or max length for text fields. ### Managing Existing Fields For each custom field, you can access management options through the action menu: Custom field management options showing edit and delete actions Available actions include: * **Edit**: Modify field (or section) properties, constraints, or organization * **Delete**: Remove the field (or section) entirely (requires confirmation for fields containing existing data for at least one business) When editing fields that already contain business data, changes may require the `force` parameter depending on whether the modification could affect any existing business data. ### Field Types and Configuration The App UI supports all the same field types available through the REST API: * **Yes/No**: A field type limited to a Yes/No option (a *boolean* field) * **Number**: A number with options to format with decimals (integer or decimal number fields with optional constraints) * **Text**: A text to describe a field freely (string fields with optional character limits) * **Select**: A list of text options to choose from (single or multiple choice from predefined options) * **Select Image**: A list of image options to choose from (multiple image choices with labels) * **Images uploader**: A button allowing the user to add images (file upload fields for image content) ## Updating Custom Field Values for Businesses Once custom fields are created, they can be populated with data for individual businesses through the Business Edit interface in the app. Simply navigate to the business you would like to update, scroll to the bottom of the page to find "Custom Fields". Business Edit page showing the Custom Fields section field values can be set. If you prefer updating your businesses using the REST API, please refer to the next section. ## REST API Operations The Custom Fields API provides comprehensive CRUD operations for managing your organization's custom fields: ### Core Endpoints | Operation | Endpoint | Description | | - | - | - | | **GET** | [`/api/v2/custom-fields`](/api-reference/custom-fields/get-custom-fields) | Retrieve all custom fields | | **POST** | [`/api/v2/custom-fields`](/api-reference/custom-fields/create-custom-fields) | Create a new custom field | | **PUT** | [`/api/v2/custom-fields/{custom_field_id}`](/api-reference/custom-fields/update-custom-field) | Update an existing custom field | | **DELETE** | [`/api/v2/custom-fields/{custom_field_id}`](/api-reference/custom-fields/delete-custom-field) | Delete a custom field | | **POST** | [`/api/v2/custom-fields/order`](/api-reference/custom-fields/order-custom-fields) | Reorder custom fields and sections | ### Managing Custom Field Values Custom field values are managed through the business endpoints: | Operation | Endpoint | Description | | - | - | - | | **GET** | [`/api/v2/business/{business_id}`](/api-reference/businesses/business-information) | Get business with custom field values | | **POST** | [`/api/v2/business/{business_id}/update`](/api-reference/businesses/update-business) | Update business custom field values | ### Query Parameters #### Force Updates When updating or deleting custom fields, use the `force` parameter to handle destructive changes: * `force=false` (default): Only allows non-destructive changes * `force=true`: Allows destructive changes that may affect existing business data For example, if you are already using a custom field named "Foo", have data saved for any businesses in that field, and you want to delete "Foo", you must set `force=true` to proceed with the update. Decreasing the `max_allowed_values` of a multiple-select field or removing possible values from a select field also requires `force=true` if any existing business data would be affected. ## REST API Examples In this walkthrough, we'll create a complete custom field setup for a restaurant chain that wants to track service levels and special amenities for each location. We'll start by creating the fields, then populate them with data for specific businesses, and finally make updates as needed. ### Creating Custom Fields Let's start by creating a few custom fields that our restaurant chain will use to categorize and track additional information about their locations. First, we'll create a single-select field to categorize our restaurants by service level: ```json theme={null} POST /api/v2/custom-fields { "name": "Service Level", "type": "SINGLE_SELECT", "possible_values": ["Premium", "Standard", "Basic"], "order": 1, "section_id": null } ``` Response: ```json theme={null} { "id": 101 } ``` Our field has been created with ID 101. We'll use this ID in subsequent operations. Next, we'll add a text field for internal notes about each location: ```json theme={null} POST /api/v2/custom-fields { "name": "Manager Notes", "type": "TEXT", "max_len": 500, "order": 2, "section_id": null } ``` Response: ```json theme={null} { "id": 102 } ``` Finally, let's create a multiple-select field to track available amenities with custom ordering: ```json theme={null} POST /api/v2/custom-fields { "name": "Available Amenities", "type": "MULTIPLE_SELECT", "possible_values": ["WiFi", "Parking", "Drive-Through", "Outdoor Seating", "Wheelchair Access"], "possible_orders": [1, 3, 2, 5, 4], "max_selected_values": 3, "order": 3, "section_id": null } ``` Response: ```json theme={null} { "id": 103 } ``` We've limited this field to 3 selections maximum using `max_selected_values` and specified custom display ordering with `possible_orders`. WiFi will appear first, Drive-Through second, Parking third, followed by Wheelchair Access and Outdoor Seating. The system will automatically generate `possible_ids` for each option in `possible_values`. ### Retrieving Your Custom Fields Now let's verify that our custom fields have been created successfully: ```json theme={null} GET /api/v2/custom-fields Response: { "custom_fields": [ { "id": 101, "name": "Service Level", "type": "SINGLE_SELECT", "possible_values": ["Premium", "Standard", "Basic"], "order": 1, "section_id": null, "section_name": null }, { "id": 102, "name": "Manager Notes", "type": "TEXT", "max_len": 500, "order": 2, "section_id": null, "section_name": null }, { "id": 103, "name": "Available Amenities", "type": "MULTIPLE_SELECT", "possible_values": ["WiFi", "Parking", "Drive-Through", "Outdoor Seating", "Wheelchair Access"], "possible_ids": ["1", "2", "3", "4", "5"], "max_selected_values": 3, "order": 3, "section_id": null, "section_name": null } ] } ``` Perfect! All three custom fields are now available for use across our organization. ### Setting Custom Field Values on Businesses With our custom fields created, let's populate them with data for a few restaurant locations: Let's set custom field values for our flagship downtown location: ```json theme={null} POST /api/v2/business/64a1b2c3d4e5f6789012345a/update { "custom_fields": { "Service Level": "Premium", "Manager Notes": "Flagship location with full-service dining and sommelier", "Available Amenities": ["WiFi", "Parking", "Outdoor Seating"] } } ``` We're selecting only 3 amenities to respect the `max_selected_values: 3` constraint we set when creating this field. Response: ```json theme={null} { "status": "success", "id": "64a1b2c3d4e5f6789012345a" } ``` Now let's configure a standard location in the suburbs: ```json theme={null} POST /api/v2/business/64a1b2c3d4e5f6789012345b/update { "custom_fields": { "Service Level": "Standard", "Manager Notes": "Suburban location with family-friendly atmosphere", "Available Amenities": ["WiFi", "Parking", "Drive-Through"] } } ``` Response: ```json theme={null} { "status": "success", "id": "64a1b2c3d4e5f6789012345b" } ``` ### Updating Custom Fields After operating for a few months, we want to expand our service level options and update some field constraints: Let's add an "Enterprise" tier for our business-focused locations and remove the "Basic" tier: ```json theme={null} PUT /api/v2/custom-fields/101 { "name": "Service Level", "type": "SINGLE_SELECT", "created_values": ["Enterprise"], "deleted_values": ["Basic"], "force": false } ``` Response: ```json theme={null} { "id": "success" } ``` We've found that 500 characters isn't enough for detailed manager notes, so let's increase the limit: ```json theme={null} PUT /api/v2/custom-fields/102 { "name": "Manager Notes", "type": "TEXT", "max_len": 1000, "section_id": null } ``` Response: ```json theme={null} { "id": "success" } ``` ### Viewing Updated Business Data Let's check how our custom field data appears when retrieving business information: ```json theme={null} GET /api/v2/business/64a1b2c3d4e5f6789012345a Response: { "id": "64a1b2c3d4e5f6789012345a", "name": "Downtown Premium Restaurant", "city": "New York", "country": "US", // ... other business fields "custom_fields": [ { "id": 101, "name": "Service Level", "type": "SINGLE_SELECT", "value": "Premium", "order": 1 }, { "id": 102, "name": "Manager Notes", "type": "TEXT", "value": "Flagship location with full-service dining and sommelier", "order": 2 }, { "id": 103, "name": "Available Amenities", "type": "MULTIPLE_SELECT", "value": ["WiFi", "Parking", "Outdoor Seating"], "possible_ids": ["1", "2", "3", "4", "5"], "max_selected_values": 3, "order": 3 } ] } ``` The custom fields are now fully integrated with the business data and can be used for filtering, reporting, or integration with other systems. ### Updating Business Custom Field Values As our business evolves, we can easily update the custom field values: Let's upgrade our downtown location to the new "Enterprise" tier and add more detailed notes: ```json theme={null} POST /api/v2/business/64a1b2c3d4e5f6789012345a/update { "custom_fields": { "Service Level": "Enterprise", "Manager Notes": "Flagship Enterprise location with full-service dining, sommelier, private dining rooms, and corporate catering services. Recently renovated with new kitchen equipment and expanded wine cellar." } } ``` Response: ```json theme={null} { "status": "success", "id": "64a1b2c3d4e5f6789012345a" } ``` Now our restaurant location has been updated to reflect the new service tier and expanded capabilities. ## Best Practices * Use descriptive names that clearly indicate the field's purpose * Group related fields into sections for better organization * Set appropriate constraints (min/max values, text lengths) to ensure data quality * Use select fields instead of text when you have a finite set of valid options * Test field constraints with sample data before deploying * Back up critical business data before making destructive changes # Sending Surveys via Email Source: https://developers.partoo.co/guides/api/resources/feedback-management/sending-feedback-emails Create email templates and send feedback email campaigns through the Feedback Management API The Feedback Management API lets you collect feedback from your customers by email. You design a reusable email template, then send a campaign to a list of recipients. Each email links to one of your feedback forms, and the responses you collect feed back into Partoo's Feedback Management. ## Prerequisites Before sending feedback emails, ensure you have: * A valid [API key](/guides/api/resources/settings/security_and_api_key_usage) with access to Feedback Management. * At least one **feedback form** configured for your organization. The campaign links recipients to this form. * A **sender email** whose domain is authorized for your organization and validated for email sending. Contact your Account Manager if you are unsure whether your domain is set up. ## How sending works A feedback email campaign ties together three things: an **email template** (how the email looks), a **feedback form** (where responses are collected), and a **recipient list** (who receives it). ```mermaid theme={null} flowchart LR A[Get email template ID] --> B[Get feedback form ID] B --> C[Get campaign requirements] C --> D[Send campaign - dry run] D --> E[Send campaign - real] ``` Validation is **all-or-nothing**: if the sender email or any recipient fails validation, the entire campaign is rejected and **no emails are sent**. The response body details every error so you can fix the list and retry. ## Step 0 — Create an email template (optional) This step is optional. Most teams design their templates visually with the WYSIWYG editor in the Partoo Web app. If you already have a template, skip to [Step 1](#step-1-get-your-email-template-id). ```bash cURL theme={null} curl -X POST 'https://api.partoo.co/v2/feedback/email-templates' \ -H 'x-APIKey: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "name": "Default Template", "subject": "We'\''d love your feedback", "title": "How did we do?", "body": "Thank you for visiting us. Please take a moment to share your experience.", "cta_type": "BUTTON", "cta_text": "Leave a review", "color": "#3B82F6", "font_family": "Arial" }' ``` ```python Python theme={null} import requests response = requests.post( "https://api.partoo.co/v2/feedback/email-templates", headers={ "x-APIKey": "YOUR_API_KEY", "Content-Type": "application/json", }, json={ "name": "Default Template", "subject": "We'd love your feedback", "title": "How did we do?", "body": "Thank you for visiting us. Please take a moment to share your experience.", "cta_type": "BUTTON", "cta_text": "Leave a review", "color": "#3B82F6", "font_family": "Arial", }, ) template_id = response.json()["id"] ``` ```javascript Node.js theme={null} const response = await fetch( "https://api.partoo.co/v2/feedback/email-templates", { method: "POST", headers: { "x-APIKey": "YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ name: "Default Template", subject: "We'd love your feedback", title: "How did we do?", body: "Thank you for visiting us. Please take a moment to share your experience.", cta_type: "BUTTON", cta_text: "Leave a review", color: "#3B82F6", font_family: "Arial", }), }, ); const {id: templateId} = await response.json(); ``` A successful response returns `201 Created` with the template's `id`. See the [Create an email template API reference](/api-reference/feedback-management/create-an-email-template) for the full field reference. ## Step 1 — Get your email template ID Templates built in the Partoo Web app are available to the API. List your organization's templates to find the `id` you want to use. ```bash cURL theme={null} curl -X GET 'https://api.partoo.co/v2/feedback/email-templates?page=1&per_page=30' \ -H 'x-APIKey: YOUR_API_KEY' ``` ```python Python theme={null} import requests response = requests.get( "https://api.partoo.co/v2/feedback/email-templates", headers={"x-APIKey": "YOUR_API_KEY"}, params={"page": 1, "per_page": 30}, ) templates = response.json()["items"] template_id = templates[0]["id"] ``` ```javascript Node.js theme={null} const params = new URLSearchParams({page: "1", per_page: "30"}); const response = await fetch( `https://api.partoo.co/v2/feedback/email-templates?${params}`, {headers: {"x-APIKey": "YOUR_API_KEY"}}, ); const {items} = await response.json(); const templateId = items[0].id; ``` See the [List email templates API reference](/api-reference/feedback-management/list-email-templates) for the full response schema and pagination options. ## Step 2 — Get your feedback form ID Each campaign links recipients to one feedback form. Search your organization's forms to find the `feedback_form_id` you want to use. ```bash cURL theme={null} curl -X GET 'https://api.partoo.co/v2/feedback/feedback_form' \ -H 'x-APIKey: YOUR_API_KEY' ``` ```python Python theme={null} import requests response = requests.get( "https://api.partoo.co/v2/feedback/feedback_form", headers={"x-APIKey": "YOUR_API_KEY"}, ) feedback_form_id = response.json()["items"][0]["id"] ``` ```javascript Node.js theme={null} const response = await fetch( "https://api.partoo.co/v2/feedback/feedback_form", { headers: {"x-APIKey": "YOUR_API_KEY"}, }, ); const {items} = await response.json(); const feedbackFormId = items[0].id; ``` See the [Search for feedback forms API reference](/api-reference/feedback-management/search-for-feedback-forms) for details. ## Step 3 — Get campaign requirements Before sending, call the requirements endpoint with your `feedback_form_id` and `template_id`. It returns the exact recipient fields and template variables your payload must include, so you know which keys to provide for every recipient. ```bash cURL theme={null} curl -X GET 'https://api.partoo.co/v2/feedback/campaign/requirements?feedback_form_id=5a3f8c2e1b4d7f9a0c6e2b18&template_id=42' \ -H 'x-APIKey: YOUR_API_KEY' ``` ```python Python theme={null} import requests response = requests.get( "https://api.partoo.co/v2/feedback/campaign/requirements", headers={"x-APIKey": "YOUR_API_KEY"}, params={ "feedback_form_id": "5a3f8c2e1b4d7f9a0c6e2b18", "template_id": 42, }, ) requirements = response.json() ``` ```javascript Node.js theme={null} const params = new URLSearchParams({ feedback_form_id: "5a3f8c2e1b4d7f9a0c6e2b18", template_id: "42", }); const response = await fetch( `https://api.partoo.co/v2/feedback/campaign/requirements?${params}`, {headers: {"x-APIKey": "YOUR_API_KEY"}}, ); const requirements = await response.json(); ``` A typical response: ```json theme={null} { "feedback_form_id": "5a3f8c2e1b4d7f9a0c6e2b18", "template_id": 42, "recipient_fields": ["email_address", "unsubscribe_url"], "variable_fields": ["first_name", "store_code"] } ``` * **`recipient_fields`**: Recipient-level fields supported by the send endpoint. * **`variable_fields`**: Template variable names each recipient must provide under `variables` (sorted alphabetically). In the example above, every recipient must supply `first_name` and `store_code`. See the [Get campaign requirements API reference](/api-reference/feedback-management/get-campaign-requirements) for the full schema. ## Step 4 — Validate with a dry run A dry run uses the same send endpoint (`POST /feedback/campaign/send`) with `is_dry_run: true`. It validates the sender and recipients **without sending any emails** — the safest way to confirm your list is correct before a real send. ```bash cURL theme={null} curl -X POST 'https://api.partoo.co/v2/feedback/campaign/send' \ -H 'x-APIKey: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "feedback_form_id": "5a3f8c2e1b4d7f9a0c6e2b18", "feedback_email_template_id": 42, "sender_email": "noreply@example.com", "sender_name": "Acme Corp", "is_dry_run": true, "recipients": [ { "email_address": "john.doe@example.com", "variables": { "first_name": "John", "store_code": "PAR-01" } } ] }' ``` ```python Python theme={null} import requests response = requests.post( "https://api.partoo.co/v2/feedback/campaign/send", headers={ "x-APIKey": "YOUR_API_KEY", "Content-Type": "application/json", }, json={ "feedback_form_id": "5a3f8c2e1b4d7f9a0c6e2b18", "feedback_email_template_id": 42, "sender_email": "noreply@example.com", "sender_name": "Acme Corp", "is_dry_run": True, "recipients": [ { "email_address": "john.doe@example.com", "variables": {"first_name": "John", "store_code": "PAR-01"}, } ], }, ) result = response.json() ``` ```javascript Node.js theme={null} const response = await fetch( "https://api.partoo.co/v2/feedback/campaign/send", { method: "POST", headers: { "x-APIKey": "YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ feedback_form_id: "5a3f8c2e1b4d7f9a0c6e2b18", feedback_email_template_id: 42, sender_email: "noreply@example.com", sender_name: "Acme Corp", is_dry_run: true, recipients: [ { email_address: "john.doe@example.com", variables: {first_name: "John", store_code: "PAR-01"}, }, ], }), }, ); const result = await response.json(); ``` The send endpoint returns `200 OK` for **both** accepted and rejected campaigns. Always inspect the `status` field rather than relying on the HTTP status code. * `status: "accepted"` — validation passed (emails enqueued, or skipped because `is_dry_run` was `true`). * `status: "failed"` — sender or recipient validation failed; no emails were sent. The error fields describe what to fix. See the [Send a feedback email campaign API reference](/api-reference/feedback-management/send-a-feedback-email-campaign) for the complete request and response schema. ## Step 5 — Send the campaign Once the dry run returns `status: "accepted"`, send for real by setting `is_dry_run: false` (or omitting it — it defaults to `false`). A successful response: ```json theme={null} { "status": "accepted", "feedback_email_campaign_id": 101, "feedback_form_id": "5a3f8c2e1b4d7f9a0c6e2b18", "feedback_template_id": 42, "recipient_count": 150 } ``` **Batch limit**: a single call accepts at most **1000 recipients**. For larger lists, split them into batches and call the endpoint multiple times. See the [Send a feedback email campaign API reference](/api-reference/feedback-management/send-a-feedback-email-campaign) for the complete request and response schema. # Custom Channels Source: https://developers.partoo.co/guides/api/resources/messages/custom-channel Connect your own messaging sources like chatbots, CRMs, or internal tools directly to Partoo This feature is available only for businesses subscribed to the Messages Product. A custom channel allows you to connect your own messaging source directly to Partoo. This enables you to centralize all your customer communications in one place while maintaining your existing messaging infrastructure. ## Prerequisites Before setting up a custom channel, ensure you have: * Active subscription to the Messages Product * [API key with ORG\_ADMIN or PROVIDER rights](/guides/api/resources/settings/security_and_api_key_usage) If you need help with any of these prerequisite, please contact your Account Manager who can guide you through the process. ## Channel configuration To integrate a custom channel, you need to contact our Account Manager to activate the channel. We'll help you set up the integration with the following information: Send to your support contact the following details for your custom channel: * **name**: Display name for your custom channel * **icon**: (Optional) URL to an image for the channel's icon * **is\_readonly**: Channel communication mode (see next step) Decide whether your channel should be read-only or bidirectional: * Messages can only be sent **TO Partoo** * Simpler setup with no webhook requirements * Ideal for notification systems or logging * Messages can be sent both ways * Replies from Partoo app or API are possible You must subscribe to the [Message Created](/api-reference/webhooks-events/message-created) webhook to receive and process replies from Partoo, as they are not automatically sent back to your system. To know more about webhooks, please refer to the [Webhooks guide](/guides/api/resources/settings/webhooks) Reach out to our support team with your configuration requirements. After configuration, you'll receive a `channel_id` that you'll need for implementing the message flow. Before you start this phase, make sure that you have received the `channel_id` from the setup phase. Also make sure that you have access to the webhook endpoints (for bidirectional channels only). ## Send messages from your custom channel to Partoo Once your custom channel is configured, you can use the message ingestion endpoint to send messages to Partoo from your custom channel. ``` POST /custom-channels/{channel_id}/messages ``` You can find more about the endpoint in the [API Reference](/api-reference/custom-channels/ingest-message). ### How the endpoint works This endpoint creates new messages in conversations that use custom channels. Key behaviors to consider: * If the conversation exists, the message is added to it * If the conversation doesn't exist, it's automatically created before adding the message * Messages are processed asynchronously for better performance * `external_conversation_id`& `external_message_id` enable you to correlate webhook messages with the corresponding conversations in your internal system. * Messages with the same `external_message_id` & `channel_id` are considered duplicates and ignored * Messages with the same `external_conversation_id` & `channel_id` are grouped in the same Partoo conversation A 200 OK response indicates the request was received and accepted for processing, but doesn't guarantee the message was successfully created. Monitor your webhook events or check the conversation to verify message delivery. ## Receive messages from Partoo to your custom channel (for bidirectional channels) If you configured your channel as bidirectional (`is_readonly: false`), you need to handle incoming replies from Partoo Set up webhook subscription for [Message Created](/api-reference/webhooks-events/message-created) events to receive replies sent from Partoo. You can find more about webhooks in the [Webhooks guide](/guides/api/resources/settings/webhooks). When Partoo users reply to messages, you'll receive webhook notifications that you need to process and route back to your system. You've successfully configured your custom messaging channel! Your integration is now ready to handle messages through Partoo's messaging platform. # Groups and Sections Source: https://developers.partoo.co/guides/api/resources/organizations/groups Learn how to organize, filter, and protect your business data in Partoo using Groups, Sections, and role-based access. ## Overview Use **Groups** and **Sections** to organize your businesses, then create Accesses to control what each `Group Manager` can see and manage. * **Section** : a logical container that holds multiple Groups (e.g., `Country`, `Service`). * **Group** : a label you assign to a business (e.g., `France`, `Bakery`). * **Access** : a set of Groups that defines a **GROUP\_MANAGER**’s permissions. ## Why use Groups? * **Easy organization** : A business can be part of multiple Groups. * **Smart filtering** : Mix Groups from different Sections to focus analytics or control permissions. * **Controlled access** : Give managers access only to the Groups they need. ## Group Architecture To illustrate the concept more clearly, we'll use a **Zoo Organization** example.\ In this model, animals are categorized across three **Sections** — **Class**, **Continent**, and **Food**. Each Section contains multiple **Groups** (for example, *Birds*, *Europe*, *Omnivore*). This analogy provides a more comprehensive and relatable way to understand how entities can belong to multiple Groups within different Sections and how filtering logic applies across them. Diagram of Sections (Class, Continent, Food) containing multiple Groups Examples of valid combinations: * `Birds / Europe / Omnivore` * `Reptiles / Africa / Carnivore` * `Fish / Asia / Herbivore` * `Amphibians / South America` ## Filtering Logic * **Within one Section** — selecting multiple Groups applies **OR** logic.\ *Example*: `Birds` **OR** `Reptiles` returns animals belonging to either class. * **Across Sections** — selecting Groups from different Sections applies **AND** logic.\ *Example*: `Europe` **AND** `Birds`**AND** `Omnivore` returns European animals that eat both plants and meat. This filtering system allows zookeepers and researchers to dynamically explore animal data without redundancy or overlap. ## Accesses for Group Managers Users with the **GROUP\_MANAGER** role work with predefined Accesses—combinations of Groups that define their scope. A single manager can hold multiple Accesses: * All omnivorous birds in Europe * All carnivorous reptiles in Africa Two separate Access filters applied: Europe/Birds/Omnivore and Africa/Reptiles/Carnivore ## Example: Applying Filters Below are practical outcomes of filter combinations. | Filters Applied | Example Animals Returned | | - | - | | `Class: Birds, Reptiles` | Crocodile, Eagle, Hawk, Owl,Canary, Turkey, Sparrow, Chicken | | `Class: Birds / Continent: Europe / Food: Omnivore` | Canary, Turkey, Sparrow, Chicken | | `Continent: Europe` | Birds (Eagle, Owl), Fish (Trout), Reptiles (Lizard) | | `No Filters Applied` | Crab, Snail, Lobster, Jellyfish, and all unclassified animals | Assign the narrowest Accesses possible. Smaller scopes reduce error risk and improve performance. ## Assign Groups and Accesses via API You can assign businesses to a group using the create group or update group endpoints. For a single business, you can specify its groups using the `groups` field during the creation or update of the business using the (create business or update business) endpoints. You can assign accesses to a `GROUP_MANAGER` user using the `accesses` field during the creation or update of the user using the (create user or update user) endpoints. If you have any questions about implementing the groups system, please reach out to our technical support team at [api@partoo.fr](mailto:api@partoo.fr). # Post Management Source: https://developers.partoo.co/guides/api/resources/posts/post-management Create and publish engaging content across Google, Facebook, Instagram, and Store Locator to boost your business visibility Posts allow businesses to share announcements, offers, events, and updates directly on connected platforms. Once published, your content appears on Google, Facebook, Instagram, and your Store Locator, helping you engage with customers and improve your online presence. For Google: When a business is connected to a Google location (action performed in Partoo app on [Partner Connection](https://app.partoo.co/settings/platforms/connection) page), existing Google Posts are automatically imported and kept in sync as Partoo Posts. If the business is later disconnected, the Google Posts published on Google will be deleted from Partoo database. ## Prerequisites Before using the Posts API, ensure you have: * Active subscription to **Posts** plan * [API key](/guides/api/resources/settings/security_and_api_key_usage) with appropriate role (Business Manager, Group Manager, Organization Manager, or Organization Admin) * Platform Integrations: Businesses must be connected to target platforms * Businesses have a `google_location_id` connected * `DIFFUSION` feature enabled * Businesses have a `facebook_page_id` connected * `DIFFUSION` feature enabled * Businesses have a `facebook_page_id` with Instagram linked * `DIFFUSION` feature enabled * No platform connection required * `STORE_LOCATOR_POSTS` feature enabled If you need help with any of these prerequisites, please contact your Account Manager who can guide you through the process. ## Understanding Post Types Different post types serve different purposes and have specific requirements: News posts are announcements and updates about your business. **Required fields:** * `summary`: Main content (max 1500 chars for Google, 10000 for Facebook, 2200 for Instagram) **Supported platforms:** * ✅ Google * ✅ Facebook * ✅ Instagram (requires at least 1 image) * ✅ Store Locator In API requests, use `"post_type": "news"` to create news posts. Event posts promote time-specific events at your business. **Required fields:** * `title`: Event name (max 58 chars) * `start_at`: Event start date/time * `end_at`: Event end date/time * `summary`: Event description (optional, max 1500 chars) **Supported platforms:** * ✅ Google only * ❌ Facebook (not supported) * ❌ Instagram (not supported) * ❌ Store Locator (not supported) Event end time must be in the future, and schedule time (if provided) must be before the end time. In API requests, use `"post_type": "event"` to create event posts. Offer posts promote deals and promotions with validity periods. **Required fields:** * `title`: Offer name (max 58 chars) * `start_at`: Offer start date/time * `end_at`: Offer end date/time * `summary`: Offer description (optional, max 1500 chars) * `coupon_code`: Discount code (optional, max 58 chars) * `offer_link`: Link to offer details (optional) * `offer_terms`: Terms and conditions (optional, max 5000 chars) **Supported platforms:** * ✅ Google only * ❌ Facebook (not supported) * ❌ Instagram (not supported) * ❌ Store Locator (not supported) Offer end time must be in the future, and schedule time (if provided) must be before the end time. In API requests, use `"post_type": "offer"` to create offer posts. ## Creating Posts All roles can create posts for the businesses they have access to. Each business gets its own individual post. **Who can create posts for multiple businesses:** * **Organization Admin & Organization Manager**: All businesses in the organization * **Group Manager**: All businesses in their assigned groups * **Business Manager**: Their assigned businesses (can be one or multiple) **About bulk\_id**: When you create posts for more than 1 business in a single request, the system assigns a shared `bulk_id` to group them together. However, only Organization Admin and Organization Manager can use the [bulk management endpoints](#managing-existing-bulks) to update/delete all posts in a bulk at once. ## Creating a post for one business All roles (Business Manager, Group Manager, Organization Manager, Organization Admin) can create posts for individual businesses they have access to. ```bash cURL theme={null} curl -X POST 'https://api.partoo.co/v2/posts' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "business_search": { "business__in": ["5409c35a97bbc544d8e26737"] }, "publishers": ["google_my_business", "facebook"], "data": { "post_type": "news", "summary": "We are excited to announce our new summer menu! Come try our fresh seasonal dishes. 🌞" } }' ``` ```python Python theme={null} import requests response = requests.post( 'https://api.partoo.co/v2/posts', headers={ 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, json={ 'business_search': { 'business__in': ['5409c35a97bbc544d8e26737'] }, 'publishers': ['google_my_business', 'facebook'], 'data': { 'post_type': 'news', 'summary': 'We are excited to announce our new summer menu! Come try our fresh seasonal dishes. 🌞' } } ) result = response.json() print(f"Post created: {result['ids']}") ``` ```javascript Node.js theme={null} const response = await fetch('https://api.partoo.co/v2/posts', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ business_search: { business__in: ['5409c35a97bbc544d8e26737'] }, publishers: ['google_my_business', 'facebook'], data: { post_type: 'news', summary: 'We are excited to announce our new summer menu! Come try our fresh seasonal dishes. 🌞' } }) }); const result = await response.json(); console.log(`Post created: ${result.ids}`); ``` ## Creating posts for multiple businesses Each business gets its own individual post. When targeting more than one business, all posts share a `bulk_id` for grouping purposes. Group Managers, Organization Managers, and Organization Admins can create posts for businesses in specific groups: ```bash cURL theme={null} curl -X POST 'https://api.partoo.co/v2/posts' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "business_search": { "group_ids__in": [111, 222] }, "publishers": ["google_my_business"], "data": { "post_type": "news", "summary": "All our locations will be closed on December 25th for the holidays. Happy holidays!" } }' ``` ```python Python theme={null} import requests response = requests.post( 'https://api.partoo.co/v2/posts', headers={ 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, json={ 'business_search': { 'group_ids__in': [111, 222] }, 'publishers': ['google_my_business'], 'data': { 'post_type': 'news', 'summary': 'All our locations will be closed on December 25th for the holidays. Happy holidays!' } } ) result = response.json() print(f"Created {len(result['data'])} posts with bulk_id") ``` ```javascript Node.js theme={null} const response = await fetch('https://api.partoo.co/v2/posts', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ business_search: { group_ids__in: [111, 222] }, publishers: ['google_my_business'], data: { post_type: 'news', summary: 'All our locations will be closed on December 25th for the holidays. Happy holidays!' } }) }); const result = await response.json(); console.log(`Created ${result.data.length} posts with bulk_id`); ``` Organization Admins and Organization Managers can create posts for all businesses in the organization: ```bash cURL theme={null} curl -X POST 'https://api.partoo.co/v2/posts' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "business_search": { "org_id__in": [789] }, "publishers": ["google_my_business"], "data": { "post_type": "news", "summary": "Extended hours for all locations during the holiday season!" } }' ``` ```python Python theme={null} import requests response = requests.post( 'https://api.partoo.co/v2/posts', headers={ 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, json={ 'business_search': { 'org_id__in': [789] }, 'publishers': ['google_my_business'], 'data': { 'post_type': 'news', 'summary': 'Extended hours for all locations during the holiday season!' } } ) result = response.json() print(f"Created {len(result['data'])} posts across organization") ``` ```javascript Node.js theme={null} const response = await fetch('https://api.partoo.co/v2/posts', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ business_search: { org_id__in: [789] }, publishers: ['google_my_business'], data: { post_type: 'news', summary: 'Extended hours for all locations during the holiday season!' } }) }); const result = await response.json(); console.log(`Created ${result.data.length} posts across organization`); ``` **What happens:** * Each business gets its own separate Post record * All posts share the same `bulk_id` (assigned internally) * To get the `bulk_id`, query one of the created posts using its `post_id` * Only ORG\_ADMIN/ORG\_MANAGER can use [bulk management endpoints](#managing-existing-bulks) to update/delete all posts at once ## Publishing event posts with time constraints Event posts are perfect for promoting time-specific events at your business locations. Prepare all required event information: * Event title (max 58 characters) * Start and end dates/times * Event description (optional) * Media files (optional) ```bash cURL theme={null} curl -X POST 'https://api.partoo.co/v2/posts' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "business_search": { "business__in": ["5409c35a97bbc544d8e26737"] }, "publishers": ["google_my_business"], "data": { "post_type": "event", "title": "Live Jazz Night", "summary": "Join us for an evening of jazz with local popular artists. Free entry!", "start_at": "2024-12-20T19:00:00Z", "end_at": "2024-12-20T23:00:00Z" } }' ``` ```python Python theme={null} import requests from datetime import datetime, timedelta # Event starts in 30 days at 7 PM and ends at 11 PM start_time = datetime.now() + timedelta(days=30) start_time = start_time.replace(hour=19, minute=0, second=0) end_time = start_time.replace(hour=23) response = requests.post( 'https://api.partoo.co/v2/posts', headers={ 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, json={ 'business_search': { 'business__in': ['5409c35a97bbc544d8e26737'] }, 'publishers': ['google_my_business'], 'data': { 'post_type': 'event', 'title': 'Live Jazz Night', 'summary': 'Join us for an evening of jazz with local popular artists. Free entry!', 'start_at': start_time.strftime('%Y-%m-%dT%H:%M:%SZ'), 'end_at': end_time.strftime('%Y-%m-%dT%H:%M:%SZ') } } ) ``` ```javascript Node.js theme={null} // Event starts in 30 days at 7 PM and ends at 11 PM const startTime = new Date(); startTime.setDate(startTime.getDate() + 30); startTime.setHours(19, 0, 0, 0); const endTime = new Date(startTime); endTime.setHours(23, 0, 0, 0); const response = await fetch('https://api.partoo.co/v2/posts', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ business_search: { business__in: ['5409c35a97bbc544d8e26737'] }, publishers: ['google_my_business'], data: { post_type: 'event', title: 'Live Jazz Night', summary: 'Join us for an evening of jazz with local popular artists. Free entry!', start_at: startTime.toISOString(), end_at: endTime.toISOString() } }) }); ``` Event posts are **only supported** on Google. Do not include Facebook, Instagram, or Store Locator as publishers for event posts. The post will be created with state `pending` and will transition to `live` once published. This process is asynchronous and may take a few minutes. ## Publishing promotional offers with validity periods Offer posts help you promote special deals, discounts, and limited-time promotions. Gather all offer information: * Offer title (max 58 characters) * Validity period (start and end dates/times) * Offer description (optional) * Coupon code (optional, max 58 characters) * Terms and conditions (optional, max 5000 characters) ```bash cURL theme={null} curl -X POST 'https://api.partoo.co/v2/posts' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "business_search": { "business__in": ["5409c35a97bbc544d8e26737"] }, "publishers": ["google_my_business"], "data": { "post_type": "offer", "title": "Summer Sale - 20% Off", "summary": "Enjoy 20% off all summer items! Limited time only.", "coupon_code": "SUMMER20", "offer_terms": "Valid on all summer collection items. Cannot be combined with other offers. Expires August 31st.", "start_at": "2024-06-01T00:00:00Z", "end_at": "2024-08-31T23:59:59Z" } }' ``` ```python Python theme={null} import requests from datetime import datetime response = requests.post( 'https://api.partoo.co/v2/posts', headers={ 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, json={ 'business_search': { 'business__in': ['5409c35a97bbc544d8e26737'] }, 'publishers': ['google_my_business'], 'data': { 'post_type': 'offer', 'title': 'Summer Sale - 20% Off', 'summary': 'Enjoy 20% off all summer items! Limited time only.', 'coupon_code': 'SUMMER20', 'offer_terms': 'Valid on all summer collection items. Cannot be combined with other offers. Expires August 31st.', 'start_at': '2024-06-01T00:00:00Z', 'end_at': '2024-08-31T23:59:59Z' } } ) if response.status_code == 200: result = response.json() print(f"Offer created successfully: {result['ids']}") ``` ```javascript Node.js theme={null} const response = await fetch('https://api.partoo.co/v2/posts', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ business_search: { business__in: ['5409c35a97bbc544d8e26737'] }, publishers: ['google_my_business'], data: { post_type: 'offer', title: 'Summer Sale - 20% Off', summary: 'Enjoy 20% off all summer items! Limited time only.', coupon_code: 'SUMMER20', offer_terms: 'Valid on all summer collection items. Cannot be combined with other offers. Expires August 31st.', start_at: '2024-06-01T00:00:00Z', end_at: '2024-08-31T23:59:59Z' } }) }); const result = await response.json(); console.log(`Offer created successfully: ${result.ids}`); ``` Offer posts are **only supported** on Google. Do not include Facebook, Instagram, or Store Locator as publishers for offer posts. ## Publishing posts at a specific future time Scheduled posts allow you to prepare content in advance and have it automatically published at a specific time. It's important to distinguish between two different time concepts: * **`schedule_time`**: When the post should be **published** to the platforms * **`start_at` / `end_at`**: The validity period of the post content (for events and offers) The `schedule_time` must be at least 2 hours in the future from the current time. You can schedule a news post, event post, or offer post. The `schedule_time` controls publication, while `start_at`/`end_at` control content validity. ```bash cURL theme={null} curl -X POST 'https://api.partoo.co/v2/posts' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "business_search": { "business__in": ["5409c35a97bbc544d8e26737"] }, "publishers": ["google_my_business", "facebook"], "data": { "post_type": "news", "summary": "Happy New Year! We wish you a prosperous 2026! 🎉", "schedule_time": "2025-01-01T00:00:00Z" } }' ``` ```python Python theme={null} import requests from datetime import datetime # Schedule post for New Year's Day at midnight schedule_time = datetime(2026, 1, 1, 0, 0, 0) response = requests.post( 'https://api.partoo.co/v2/posts', headers={ 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, json={ 'business_search': { 'business__in': ['5409c35a97bbc544d8e26737'] }, 'publishers': ['google_my_business', 'facebook'], 'data': { 'post_type': 'news', 'summary': 'Happy New Year! We wish you a prosperous 2026! 🎉', 'schedule_time': schedule_time.strftime('%Y-%m-%dT%H:%M:%SZ') } } ) ``` ```javascript Node.js theme={null} // Schedule post for New Year's Day at midnight const scheduleTime = new Date('2026-01-01T00:00:00Z'); const response = await fetch('https://api.partoo.co/v2/posts', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ business_search: { business__in: ['5409c35a97bbc544d8e26737'] }, publishers: ['google_my_business', 'facebook'], data: { post_type: 'news', summary: 'Happy New Year! We wish you a prosperous 2026! 🎉', schedule_time: scheduleTime.toISOString() } }) }); ``` The post will be created with state `scheduled` and will automatically transition to `pending` at the scheduled time, then to `live` once published. You can update or delete scheduled posts before they're published. Once they enter the `pending` state, updates are no longer possible (but deletion still works). ## Creating drafts requiring approval before publishing Draft posts allow organization admins to create posts that require validation from Business Managers or Group Managers before being published. **Draft Post Requirements:** * User must have `ORG_ADMIN` role * Organization must have `DRAFT_POST` feature enabled * Organization must have more than 1 business * Local users (Business Managers or Group Managers) must exist to validate drafts Verify you have permission to create draft posts: ```bash cURL theme={null} curl -X GET 'https://api.partoo.co/v2/posts/allowed_operations' \ -H 'Authorization: Bearer YOUR_API_KEY' ``` ```python Python theme={null} import requests response = requests.get( 'https://api.partoo.co/v2/posts/allowed_operations', headers={'Authorization': 'Bearer YOUR_API_KEY'} ) permissions = response.json() if permissions['create_draft_posts']: print("You can create draft posts!") if permissions['validate_draft_posts']: print("You can validate draft posts!") ``` ```javascript Node.js theme={null} const response = await fetch( 'https://api.partoo.co/v2/posts/allowed_operations', { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } } ); const permissions = await response.json(); if (permissions.create_draft_posts) { console.log('You can create draft posts!'); } if (permissions.validate_draft_posts) { console.log('You can validate draft posts!'); } ``` Create a post that requires validation before publishing: ```bash cURL theme={null} curl -X POST 'https://api.partoo.co/v2/posts' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "business_search": { "group_ids__in": [111, 222] }, "publishers": ["google_my_business", "facebook"], "is_draft": true, "send_notifications": true, "data": { "post_type": "news", "summary": "Exciting announcement coming soon! Stay tuned.", "expiration_time": "2024-12-31T23:59:59Z" } }' ``` ```python Python theme={null} import requests from datetime import datetime, timedelta # Draft expires in 7 days expiration = datetime.now() + timedelta(days=7) response = requests.post( 'https://api.partoo.co/v2/posts', headers={ 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, json={ 'business_search': { 'group_ids__in': [111, 222] }, 'publishers': ['google_my_business', 'facebook'], 'is_draft': True, 'send_notifications': True, 'data': { 'post_type': 'news', 'summary': 'Exciting announcement coming soon! Stay tuned.', 'expiration_time': expiration.strftime('%Y-%m-%dT%H:%M:%SZ') } } ) if response.status_code == 200: result = response.json() print(f"Draft created: {result['ids']}") print("Notification emails sent to Business/Group Managers") ``` ```javascript Node.js theme={null} // Draft expires in 7 days const expiration = new Date(); expiration.setDate(expiration.getDate() + 7); const response = await fetch('https://api.partoo.co/v2/posts', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ business_search: { group_ids__in: [111, 222] }, publishers: ['google_my_business', 'facebook'], is_draft: true, send_notifications: true, data: { post_type: 'news', summary: 'Exciting announcement coming soon! Stay tuned.', expiration_time: expiration.toISOString() } }) }); const result = await response.json(); console.log(`Draft created: ${result.ids}`); console.log('Notification emails sent to Business/Group Managers'); ``` When `send_notifications: true`, all Business Managers and Group Managers with access to the businesses will receive an email notification about the draft post requiring validation. Draft posts **must** include an `expiration_time`. If not validated before this time, the draft will expire and cannot be published. Business Managers or Group Managers can validate drafts by updating them: ```bash cURL theme={null} curl -X PUT 'https://api.partoo.co/v2/posts/POST_ID' \ -H 'Authorization: Bearer BM_OR_GM_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "summary": "Updated announcement: Grand opening next week!" }' ``` ```python Python theme={null} import requests # Business Manager or Group Manager validates the draft response = requests.put( f'https://api.partoo.co/v2/posts/{post_id}', headers={ 'Authorization': 'Bearer BM_OR_GM_API_KEY', 'Content-Type': 'application/json' }, json={ 'summary': 'Updated announcement: Grand opening next week!' } ) if response.status_code == 200: print("Draft validated and will be published!") ``` ```javascript Node.js theme={null} // Business Manager or Group Manager validates the draft const response = await fetch(`https://api.partoo.co/v2/posts/${postId}`, { method: 'PUT', headers: { 'Authorization': 'Bearer BM_OR_GM_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ summary: 'Updated announcement: Grand opening next week!' }) }); if (response.ok) { console.log('Draft validated and will be published!'); } ``` Once a Business Manager or Group Manager updates the draft, it transitions from `to_validate` to `pending` and will be published to the selected platforms. ## Including images in your posts Images make your posts more engaging and increase visibility on platforms. Different platforms have different image requirements: * **Limit**: 1 image * **Min size**: 250 × 250px * **Max size**: 10000 × 10000px * **Max weight**: 5MB * **Formats**: JPEG, JPG, PNG * **Limit**: Up to 10 images * **Max weight**: 10MB * **Formats**: JPEG, JPG, PNG, GIF * **Limit**: 1-10 images (at least 1 required) * **Max weight**: 5MB * **Formats**: JPEG, JPG only * **Limit**: 1 image * **Max weight**: 5MB * **Formats**: JPEG, JPG, PNG Add images to your posts using the `image_url` field: ```bash cURL theme={null} curl -X POST 'https://api.partoo.co/v2/posts' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "business_search": { "business__in": ["5409c35a97bbc544d8e26737"] }, "publishers": ["google_my_business", "instagram"], "data": { "post_type": "news", "summary": "Check out our brand new storefront!", "image_url": "https://example.com/storefront-image.jpg" } }' ``` ```python Python theme={null} import requests response = requests.post( 'https://api.partoo.co/v2/posts', headers={ 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, json={ 'business_search': { 'business__in': ['5409c35a97bbc544d8e26737'] }, 'publishers': ['google_my_business', 'instagram'], 'data': { 'post_type': 'news', 'summary': 'Check out our brand new storefront!', 'image_url': 'https://example.com/storefront-image.jpg' } } ) ``` ```javascript Node.js theme={null} const response = await fetch('https://api.partoo.co/v2/posts', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ business_search: { business__in: ['5409c35a97bbc544d8e26737'] }, publishers: ['google_my_business', 'instagram'], data: { post_type: 'news', summary: 'Check out our brand new storefront!', image_url: 'https://example.com/storefront-image.jpg' } }) }); ``` For platforms that support multiple images (Facebook, Instagram), provide an array of URL strings: ```bash cURL theme={null} curl -X POST 'https://api.partoo.co/v2/posts' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "business_search": { "business__in": ["5409c35a97bbc544d8e26737"] }, "publishers": ["facebook", "instagram"], "data": { "post_type": "news", "summary": "Our team had an amazing time at the conference!", "image_url": [ "https://example.com/photo1.jpg", "https://example.com/photo2.jpg", "https://example.com/photo3.jpg" ] } }' ``` ```python Python theme={null} import requests response = requests.post( 'https://api.partoo.co/v2/posts', headers={ 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, json={ 'business_search': { 'business__in': ['5409c35a97bbc544d8e26737'] }, 'publishers': ['facebook', 'instagram'], 'data': { 'post_type': 'news', 'summary': 'Our team had an amazing time at the conference!', 'image_url': [ 'https://example.com/photo1.jpg', 'https://example.com/photo2.jpg', 'https://example.com/photo3.jpg' ] } } ) ``` ```javascript Node.js theme={null} const response = await fetch('https://api.partoo.co/v2/posts', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ business_search: { business__in: ['5409c35a97bbc544d8e26737'] }, publishers: ['facebook', 'instagram'], data: { post_type: 'news', summary: 'Our team had an amazing time at the conference!', image_url: [ 'https://example.com/photo1.jpg', 'https://example.com/photo2.jpg', 'https://example.com/photo3.jpg' ] } }) }); ``` * **Instagram:** Requires at least 1 image (posts without images will fail). Supports JPEG/JPG only. * **Google & Store Locator:** Only support 1 image per post * **Facebook:** Supports up to 10 images ## Managing Existing Bulks Once you've created posts for multiple businesses (which automatically generates a `bulk_id` internally), Organization Admins and Organization Managers can use bulk management endpoints to search, update, or delete all posts in a bulk at once. To get the `bulk_id`, you need to retrieve one of the created posts using its `post_id` (from the create response). The post object contains the `bulk_id` field. **Role Restriction**: Bulk management endpoints (`/posts/bulks`, `/posts/count_bulk`, `/posts/delete_bulk`, `/posts/edit_bulk`) are restricted to Organization Admin and Organization Manager roles only. While Group Managers can **create** posts for multiple businesses (which generates a bulk\_id), they **cannot** use the bulk management endpoints to search, update, or delete those bulks. ## Finding and tracking posts in a bulk Use the bulk search endpoint to retrieve all posts in a specific bulk. You can use the `bulk_id` if you know it, or search by business/group to find your posts. ```bash cURL theme={null} curl -X GET 'https://api.partoo.co/v2/posts/bulks?bulk_id=12345' \ -H 'Authorization: Bearer YOUR_API_KEY' ``` ```python Python theme={null} import requests response = requests.get( 'https://api.partoo.co/v2/posts/bulks', headers={'Authorization': 'Bearer YOUR_API_KEY'}, params={'bulk_id': 12345} ) posts = response.json()['posts'] print(f"Found {len(posts)} posts in this bulk") # Check states states = {} for post in posts: state = post['state'] states[state] = states.get(state, 0) + 1 print("Post states distribution:") for state, count in states.items(): print(f" {state}: {count} posts") ``` ```javascript Node.js theme={null} const response = await fetch( 'https://api.partoo.co/v2/posts/bulks?bulk_id=12345', { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } } ); const data = await response.json(); console.log(`Found ${data.posts.length} posts in this bulk`); // Check states const states = {}; data.posts.forEach(post => { states[post.state] = (states[post.state] || 0) + 1; }); console.log('Post states distribution:'); Object.entries(states).forEach(([state, count]) => { console.log(` ${state}: ${count} posts`); }); ``` The `bulk_id` parameter is optional. Without it, `/posts/bulks` returns the list of all posts in bulk. You can combine `bulk_id` with other filters like `state__in`, `topic_type`, etc. The first post in results will contain the `bulk_id` field. ## Getting the total count Get the total count of posts in a bulk without retrieving all the data: ```bash cURL theme={null} curl -X GET 'https://api.partoo.co/v2/posts/count_bulk/12345' \ -H 'Authorization: Bearer YOUR_API_KEY' ``` ```python Python theme={null} import requests response = requests.get( f'https://api.partoo.co/v2/posts/count_bulk/{bulk_id}', headers={'Authorization': 'Bearer YOUR_API_KEY'} ) count = response.json()['count'] print(f"Total posts in bulk: {count}") ``` ```javascript Node.js theme={null} const response = await fetch( `https://api.partoo.co/v2/posts/count_bulk/${bulkId}`, { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } } ); const data = await response.json(); console.log(`Total posts in bulk: ${data.count}`); ``` ## Modifying content across multiple posts You can update all posts in a bulk simultaneously, which is useful for correcting errors or updating information. ```bash cURL theme={null} curl -X POST 'https://api.partoo.co/v2/posts/edit_bulk' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "bulk_id": 12345, "post_data": { "summary": "UPDATED: Extended hours continue through January 15th!" } }' ``` ```python Python theme={null} import requests response = requests.post( 'https://api.partoo.co/v2/posts/edit_bulk', headers={ 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, json={ 'bulk_id': 12345, 'post_data': { 'summary': 'UPDATED: Extended hours continue through January 15th!' } } ) result = response.json() print(f"Updated {result['edited']} posts") ``` ```javascript Node.js theme={null} const response = await fetch('https://api.partoo.co/v2/posts/edit_bulk', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ bulk_id: 12345, post_data: { summary: 'UPDATED: Extended hours continue through January 15th!' } }) }); const result = await response.json(); console.log(`Updated ${result.edited} posts`); ``` **Platform Behavior:** * **Google & Facebook:** Updates propagate asynchronously (a few minutes delay) * **Store Locator:** Updates apply instantly * **Instagram:** Cannot be edited once live (API limitation) ## Removing multiple posts at once Delete all posts in a bulk when content is no longer relevant or needs to be removed. ```bash cURL theme={null} curl -X POST 'https://api.partoo.co/v2/posts/delete_bulk' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "bulk_id": 12345 }' ``` ```python Python theme={null} import requests response = requests.post( 'https://api.partoo.co/v2/posts/delete_bulk', headers={ 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, json={ 'bulk_id': 12345 } ) result = response.json() print(f"Deleted {result['deleted']} posts") ``` ```javascript Node.js theme={null} const response = await fetch('https://api.partoo.co/v2/posts/delete_bulk', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ bulk_id: 12345 }) }); const result = await response.json(); console.log(`Deleted ${result.deleted} posts`); ``` **Deletion Behavior:** * Published posts transition through `pending_deleted` (asynchronous, a few minutes) * Unpublished posts are deleted immediately * **Instagram:** Only removes Partoo records, not the actual Instagram post (manual deletion required) ## Platform-Specific Guidelines Quick reference for key differences between platforms: **Supported Post Types:** News, Event, Offer **Key Limits:** * Summary: 1500 characters * Title: 58 characters (events/offers) * Offer terms: 5000 characters * Images: 1 per post Only platform supporting all three post types (News, Event, Offer). **Supported Post Types:** News only **Key Limits:** * Summary: 10,000 characters * Images: Up to 10 **Capabilities:** * ✅ Can edit after publishing * ✅ Analytics available (impressions, clicks) **Supported Post Types:** News only **Key Limits:** * Summary: 2200 characters * Images: 1-10 (at least 1 required) **Capabilities:** * ✅ Analytics available (reach, interactions) * ❌ Cannot edit once live * ❌ Cannot delete from Instagram via API Instagram posts cannot be edited or deleted once published. Plan carefully before posting. **Supported Post Types:** News only **Key Limits:** * Summary: No limit * Images: 1 per post **Capabilities:** * ✅ Can edit and delete freely * ✅ No external connection required * ❌ No analytics available ## Post Lifecycle and States Understanding post states helps you track the publishing process and troubleshoot issues: * `to_validate`: draft post awaiting validation from a Business Manager or Group Manager * `scheduled`: scheduled for future publishing at the specified `schedule_time` * `pending`: queued for publishing * `live`: successfully published * `to_configure`: configuration error * `error`: publisher error * `pending_deleted`: queued for deletion * `deleted`: successfully deleted from platforms and Partoo * `expired`: draft post expired before validation, or post passed its `end_at` date * Draft posts: `to_validate` → `pending` (after validation) → `live` * Scheduled posts: `scheduled` → `pending` (at schedule time) → `live` * Immediate posts: `pending` → `live` (or `error`/`to_configure` on failure) * Deletions: → `pending_deleted` → `deleted` ### Monitoring Post Progress State transitions are asynchronous. To monitor post status: **Use the search endpoint** `GET /api/v2/posts` with filters like `state__in=live` or `state__in=pending` to check if posts are published successfully. The `/state` endpoint (`GET /api/v2/posts/{post_id}/state`) **only returns error information** for publishers in `to_configure` state. It does NOT show live, pending, scheduled, or `error` state posts. Use it only for troubleshooting configuration issues. ### Troubleshooting Failed Posts If your post enters `to_configure` state, use the state diagnostics endpoint to understand what configuration is missing. The `/state` endpoint only returns publishers in `to_configure` state. An empty response `{}` means no configuration errors were detected (posts may be pending, scheduled, live, or in other error states). ```bash cURL theme={null} curl -X GET 'https://api.partoo.co/v2/posts/12345/state' \ -H 'Authorization: Bearer YOUR_API_KEY' ``` ```python Python theme={null} import requests response = requests.get( f'https://api.partoo.co/v2/posts/{post_id}/state', headers={'Authorization': 'Bearer YOUR_API_KEY'} ) state_info = response.json() if not state_info: print("✓ No configuration errors detected") else: print("Configuration errors found:") for platform, info in state_info.items(): print(f"\n{platform}:") print(f" State: {info['state']}") print(f" Error: {info.get('error_message', 'N/A')}") print(f" Config needed: {info.get('expected_error_message', 'N/A')}") ``` ```javascript Node.js theme={null} const response = await fetch( `https://api.partoo.co/v2/posts/${postId}/state`, { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } } ); const stateInfo = await response.json(); if (Object.keys(stateInfo).length === 0) { console.log('✓ No configuration errors detected'); } else { console.log('Configuration errors found:'); Object.entries(stateInfo).forEach(([platform, info]) => { console.log(`\n${platform}:`); console.log(` State: ${info.state}`); console.log(` Error: ${info.error_message || 'N/A'}`); console.log(` Config needed: ${info.expected_error_message || 'N/A'}`); }); } ``` The `expected_error_message` field contains an error key indicating what configuration is missing (e.g., `"publisher_connection_required"`, `"business_is_not_subscribed_to_pm"`). # Retrieve Reviews Source: https://developers.partoo.co/guides/api/resources/reviews/retrieve-reviews Learn how to effectively retrieve and manage reviews from Google, Facebook and TripAdvisor, and how to bring in your own reviews through a custom partner This feature is available only for businesses subscribed to Review Management. Partoo centralizes all business reviews from Google, Facebook, and TripAdvisor platforms, providing a unified API to retrieve and manage them efficiently. It also hosts the reviews you collect **outside** those platforms, on your own app, a marketplace, or a delivery service, through a [custom review partner](#custom-review-partners) you can push yourself. ## Prerequisites Before retrieving reviews, ensure you have: * Active subscription to the Review Management * [API key with Business Manager role or higher](/guides/api/resources/settings/security_and_api_key_usage) * Platform Integrations: Ensure your platforms are integrated properly * Valid Google My Business location ID (`google_location_id`) * Active OAuth account with proper scopes * GMB location must be linked to the business * Valid Facebook page ID (`facebook_page_id`) * Active OAuth account with review permissions * Facebook page must be linked to the business * Valid TripAdvisor location ID (`tripadvisor_location_id`) * Active API credentials * **Rate Limit**: Maximum 50 reviews per request, 50 requests per second * A custom partner created for your organization, and its `partner_slug` * The partner listed by `GET /review-partners` with `is_custom: true` If you need help with any of these prerequisites, please contact your Account Manager who can guide you through the process. ## How the Reviews Mechanism Works Partoo automatically collects reviews from Google, Facebook, and TripAdvisor platforms and makes them available through a unified API. ### Review Collection * **Scheduled fetching**: Reviews are collected daily at different times for each platform: * Google My Business: 8:15 PM UTC * Facebook: 7:00 PM UTC * TripAdvisor: 8:00 PM UTC * **24-hour delay**: New reviews may take up to 24 hours to appear in the API * **Live fetch**: Google My Business reviews are fetched when Google sends webhook notifications * **Platform integration**: Only reviews from connected platforms are available * **Custom partners**: nothing is collected, you push the reviews, and they are available immediately ### Review States Each review has one of these states: * **`treated`**: Has a reply or was marked as treated * **`not_treated`**: No reply yet and not marked as treated * **`deleted`**: Was removed by the user on the original platform * **`pending_auto_reply`**: Queued for automatic response * **`treated_auto_reply`**: Has a reply via automatic response **Important**: Unless they are from custom partners you handle on your side, you can only reply to reviews via the API, not **modify** or **delete** the original review content. ### Reply Templates Reply templates help you respond quickly to reviews with predefined messages. They're designed for use within the Partoo application. You cannot access a formatted template with prefilled placeholders from the API. However, you can manage these templates through the API: * Browse through existing reply templates * Create new reply templates * Delete reply templates ## Custom Review Partners A **custom review partner** is a source of reviews Partoo does not synchronize itself: your own app, a marketplace, a delivery platform. You push those reviews through the API, and they then behave like any other reviews: searchable, repliable, and carried by the `review_created` and `review_updated` webhooks. Replies written in Partoo travel the other way: they are [sent back to you](#get-the-replies-back) so you can publish them on your platform. ### What you need Custom partners are set up by Partoo. Contact your Account Manager with the platform you want to bring in, and you get back a **partner slug**, for example `my_partner`, that identifies it in every call. ```bash theme={null} GET /review-partners ``` Your custom partners are the entries flagged `is_custom: true`. A partner missing from that list is not enabled for your organization yet, and pushing reviews to it is refused. Pushing and deleting reviews requires an API key whose user is an `ORG_ADMIN` **and** carries the `review_edit` permission. You can only push for businesses of your own organization. ### Push your reviews ```bash theme={null} POST /reviews ``` ```json theme={null} { "partner_slug": "my_partner", "external_id": "mp-review-8f21c0", "business_id": "5409c35a97bbc544d8e26737", "rating": 4, "content": "Commande livrée en avance, tout était chaud. Merci !", "author": { "display_name": "Camille D." }, "date": "2026-09-15T18:32:11+02:00", "link": "https://www.my_partner.com/reviews/8f21c0", "reply": { "content": "Merci pour votre retour, à très bientôt !", "date": "2026-09-16T09:04:55+02:00" } } ``` The pair (`partner_slug`, `external_id`) identifies the review: the first call creates it, and every later call with the same pair updates it in place. Dates must carry their UTC offset (`+02:00`, `Z`). Partoo stores them in UTC and displays them in the timezone of the business. ### Correct and delete * **Correct a review**: push it again with the same `partner_slug` and `external_id`. Rating, content, author, dates, link and reply are all updated. * **Delete a review**: `DELETE /reviews/{review_id}`, using the Partoo `id` returned by the push. ### Read them back ```bash theme={null} # The reviews of one of your custom partners GET /reviews?partner=my_partner ``` The complete payload, and every error the push and delete endpoints can return, are documented in the [API Reference](/api-reference/reviews/push-a-review-from-a-custom-partner). ### Get the replies back Your teams answer those reviews inside Partoo, from the app or through `POST /comments`. Partoo cannot publish that answer on your platform, it is yours, so it hands it back to you: every reply **written**, **edited** or **deleted** on one of your custom-partner reviews calls the endpoint you gave us, and you publish it on your side. | Event | Sent when | Payload | | - | - | - | | `custom_reply_created` | A reply is added to one of your reviews | The review and the reply | | `custom_reply_updated` | An existing reply is edited | The review and the new reply | | `custom_reply_deleted` | A reply is removed | The review only | ```json theme={null} { "type": "custom_reply_created", "payload": { "business_id": "5409c35a97bbc544d8e26737", "partner_slug": "my_partner", "review_external_id": "mp-review-8f21c0", "reply": { "content": "Merci pour votre retour, à très bientôt !", "date": "2026-09-16T09:04:55+02:00", "update_date": null, "author_name": "Camille Durand" } } } ``` These three events can be setup from **Settings > Integrations > Webhooks** or by API as explained on the [Webhooks documentation](/guides/api/resources/settings/webhooks/index). ## Tips to Retrieve Reviews Effectively Start with the main search endpoint to retrieve reviews: ``` GET /reviews ``` You can find the complete endpoint documentation in the [API Reference](/api-reference/reviews/search-for-reviews). Use the available filters to narrow down your results: ```bash theme={null} # Get reviews for specific businesses GET /reviews?business__in=5409c35a97bbc544d8e26737,60b2645fb12ff60643ef8344 ``` ```bash theme={null} # Get only untreated reviews GET /reviews?state__in=not_treated # Get treated reviews GET /reviews?state__in=treated # Exclude deleted reviews (by default deleted reviews are returned) GET /reviews?state__notin=deleted ``` ```bash theme={null} # Get reviews from specific platforms GET /reviews?partner=google_my_business GET /reviews?partner=facebook GET /reviews?partner=tripadvisor # Get reviews from one of your custom partners GET /reviews?partner=my_partner ``` `GET /review-partners` returns every slug you can filter on, yours included. ```bash theme={null} # Get reviews from a specific date range GET /reviews?update_date__gte=2024-01-01&update_date__lte=2024-01-31 ``` Handle large datasets efficiently with cursor-based pagination: ```bash theme={null} # Enables cursor-based pagination mode GET /reviews?cursor=1 # Subsequent pages using cursor GET /reviews?next_cursor=eyJ1cGRhdGVfZGF0ZSI6IjIwMjQtMDEtMDEiLCJpZCI6MTIzfQ== ``` The default page size is 30 reviews per page, with a maximum of 100 reviews per page. Use cursor-based pagination for better performance with large datasets. Search for specific content within reviews: ```bash theme={null} # Search for reviews containing specific keywords GET /reviews?keywords=excellent,amazing,great ``` Keywords are searched across review content, author names, and platform-specific fields. Maximum 12 keywords allowed. Order your results for better management: ```bash theme={null} # Sort by creation date (newest first) GET /reviews?ordering=-date # Sort by rating (highest first) GET /reviews?ordering=-rating # Sort by status GET /reviews?ordering=state ``` Available ordering fields: `id`, `author_name`, `date`, `update_date`, `rating`, `state`, `title`, `partner`. Prefix with `-` for descending order. # Review Booster Source: https://developers.partoo.co/guides/api/resources/reviews/review-booster Boost your Google reviews through the Review Booster API This feature is available only for businesses subscribed to Review Booster. The Review Booster allows you to send SMS invitations to customers, encouraging them to leave reviews on Google. This feature helps you collect more reviews and improve your online presence by reaching customers directly via text message. ## Prerequisites Before using the Review Booster API, ensure you have: * Active subscription to Review Booster * Valid [API key](/guides/api/resources/settings/security_and_api_key_usage) * Write access on the business for sending invitations * Google My Business Integration: Your business must be connected to a valid Google My Business location If you need help with any of these prerequisites, please contact your Account Manager who can guide you through the process. The Review Booster cannot be tested in the Sandbox environment as it requires an active Google My Business connection and a valid subscription. ## How Review Booster Works The Review Booster allows you to proactively request reviews from your customers by sending them personalized SMS messages containing a direct link to leave a review on your Google Business Profile. ### SMS Invitation Flow 1. **Configure sender name**: Set up a branded expeditor name that customers will see instead of a phone number 2. **Create or customize template**: Use placeholders to personalize your message 3. **Send invitation**: The system generates a unique review link and sends the SMS to the customer 4. **Track delivery**: Monitor the status of each invitation (created, sent, delivered, or failed) 5. **Customer reviews**: Customers click the link in the SMS and are directed to leave a review on Google ### Anti-Spam Protection To prevent spamming and maintain compliance with messaging regulations: * **10-day cooldown period**: A new SMS can only be sent to a specific phone number after 10 days since the last SMS was sent * **Duplicate detection**: Use the search endpoint to check if an invitation was already sent to a customer * **Force override**: You can use the `force` parameter to bypass the cooldown period when necessary Overriding the anti-spam protection with the `force` parameter should be used sparingly to avoid customer complaints and maintain compliance with messaging regulations. ### Monthly Quotas Review Booster has monthly sending limits to ensure fair usage and cost management: * **Default quota**: Each business starts with 100 SMS invitations per month * **Automatic reset**: Quotas reset at the beginning of each month based on the business's timezone * **Quota tracking**: The system tracks remaining invitations and prevents sending when the limit is reached * **Error handling**: When the quota is exhausted, you'll receive an error: `rb_monthly_limit_reached_for_business` * **Custom quotas**: Your quota can be adjusted (between 1-1000 per month) by your Account Manager through the admin panel if your business needs differ from the default ## Implementing Review Booster Follow these steps to integrate Review Booster into your application: Before sending invitations, set up a sender name for your business. The sender name must be alphanumeric only, max 11 characters, with one space allowed. See the [Configuring Your Sender Name](#configuring-your-sender-name) section below for detailed rules and best practices. ```bash cURL theme={null} curl -X POST 'https://api.partoo.co/v2/review_booster/expeditor' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "business_id": "5409c35a97bbc544d8e26737", "expeditor_name": "MyBusiness" }' ``` ```python Python theme={null} import requests response = requests.post( 'https://api.partoo.co/v2/review_booster/expeditor', headers={ 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, json={ 'business_id': '5409c35a97bbc544d8e26737', 'expeditor_name': 'MyBusiness' } ) ``` ```javascript Node.js theme={null} const response = await fetch('https://api.partoo.co/v2/review_booster/expeditor', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ business_id: '5409c35a97bbc544d8e26737', expeditor_name: 'MyBusiness' }) }); ``` Customize your reusable template that will be used for all future invitations. If you skip this step, a default template will be created automatically when you send your first invitation. **Template placeholders**: Use `${client_name}`, `${business_name}`, and `${url}` (required). Max 250 characters excluding placeholders. See the [Working with SMS Templates](#working-with-sms-templates) section below for detailed information about placeholders, constraints, and examples. ```bash cURL theme={null} curl -X PUT 'https://api.partoo.co/v2/review_booster/template' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "template": "Hello ${client_name}! Thank you for visiting ${business_name}. Share your experience: ${url}" }' ``` ```python Python theme={null} import requests response = requests.put( 'https://api.partoo.co/v2/review_booster/template', headers={ 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, json={ 'template': 'Hello ${client_name}! Thank you for visiting ${business_name}. Share your experience: ${url}' } ) ``` ```javascript Node.js theme={null} const response = await fetch('https://api.partoo.co/v2/review_booster/template', { method: 'PUT', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ template: 'Hello ${client_name}! Thank you for visiting ${business_name}. Share your experience: ${url}' }) }); ``` Before sending, check if the customer was recently contacted: ```bash cURL theme={null} curl -X GET 'https://api.partoo.co/v2/review_booster/search-invitation?business_id=5409c35a97bbc544d8e26737&target_phone=%2B33647385968&after=1559148288' \ -H 'Authorization: Bearer YOUR_API_KEY' ``` ```python Python theme={null} import requests import time # Get timestamp from 10 days ago ten_days_ago = int(time.time()) - (10 * 24 * 60 * 60) response = requests.get( 'https://api.partoo.co/v2/review_booster/search-invitation', headers={'Authorization': 'Bearer YOUR_API_KEY'}, params={ 'business_id': '5409c35a97bbc544d8e26737', 'target_phone': '+33647385968', 'after': ten_days_ago } ) ``` ```javascript Node.js theme={null} // Get timestamp from 10 days ago const tenDaysAgo = Math.floor(Date.now() / 1000) - (10 * 24 * 60 * 60); const response = await fetch( `https://api.partoo.co/v2/review_booster/search-invitation?business_id=5409c35a97bbc544d8e26737&target_phone=%2B33647385968&after=${tenDaysAgo}`, { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } } ); ``` You can find more about the endpoint in the [Search Invitations API Reference](/api-reference/review-booster/search-for-an-invitation-matching-a-set-of-criteria). You have two options for SMS content when sending invitations: 1. **Using your template** - Uses your saved template (or default if not customized) with placeholders automatically filled 2. **Using custom content** - Provide unique `invite_content` for this specific invitation only Choose the approach that works best for your use case: ```bash cURL theme={null} curl -X POST 'https://api.partoo.co/v2/review_booster/send_invitation' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "business_id": "5409c35a97bbc544d8e26737", "target_phone": "+33647385968", "target_name": "John Doe" }' ``` ```python Python theme={null} import requests response = requests.post( 'https://api.partoo.co/v2/review_booster/send_invitation', headers={ 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, json={ 'business_id': '5409c35a97bbc544d8e26737', 'target_phone': '+33647385968', 'target_name': 'John Doe' } ) ``` ```javascript Node.js theme={null} const response = await fetch('https://api.partoo.co/v2/review_booster/send_invitation', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ business_id: '5409c35a97bbc544d8e26737', target_phone: '+33647385968', target_name: 'John Doe' }) }); ``` ```bash cURL theme={null} curl -X POST 'https://api.partoo.co/v2/review_booster/send_invitation' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "business_id": "5409c35a97bbc544d8e26737", "target_phone": "+33647385968", "target_name": "John Doe", "invite_content": "Hi John! Thanks for your visit. Leave us a review: @link" }' ``` ```python Python theme={null} import requests response = requests.post( 'https://api.partoo.co/v2/review_booster/send_invitation', headers={ 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, json={ 'business_id': '5409c35a97bbc544d8e26737', 'target_phone': '+33647385968', 'target_name': 'John Doe', 'invite_content': 'Hi John! Thanks for your visit. Leave us a review: @link' } ) ``` ```javascript Node.js theme={null} const response = await fetch('https://api.partoo.co/v2/review_booster/send_invitation', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ business_id: '5409c35a97bbc544d8e26737', target_phone: '+33647385968', target_name: 'John Doe', invite_content: 'Hi John! Thanks for your visit. Leave us a review: @link' }) }); ``` When using `invite_content`, you must include `@link`. The system will automatically replace `@link` with the review URL. Maximum 286 characters allowed, unicode characters are not accepted. A successful response includes an `invitation_id` that you can use to track the delivery status. You can find more about the endpoint in the [Send Invitation API Reference](/api-reference/review-booster/send-a-review-invitation). Monitor the delivery status of your invitation: ```bash cURL theme={null} curl -X GET 'https://api.partoo.co/v2/review_booster/invitation_status?invitation_id=3d90efec-0d7f-4960-98c0-951d58dc14cb' \ -H 'Authorization: Bearer YOUR_API_KEY' ``` ```python Python theme={null} import requests response = requests.get( 'https://api.partoo.co/v2/review_booster/invitation_status', headers={'Authorization': 'Bearer YOUR_API_KEY'}, params={'invitation_id': '3d90efec-0d7f-4960-98c0-951d58dc14cb'} ) status = response.json()['status'] print(f"Invitation status: {status}") ``` ```javascript Node.js theme={null} const response = await fetch( 'https://api.partoo.co/v2/review_booster/invitation_status?invitation_id=3d90efec-0d7f-4960-98c0-951d58dc14cb', { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } } ); const data = await response.json(); console.log(`Invitation status: ${data.status}`); ``` Each invitation goes through one of these lifecycle states: * **`CREATED`**: Invitation has been created in the system * **`SENT`**: SMS has been sent to the mobile carrier * **`DELIVERED`**: SMS has been successfully delivered to the customer's device * **`FAILED_SEND`**: SMS failed to be sent to the carrier * **`FAILED_DELIVERY`**: SMS was sent but could not be delivered to the customer The status is updated in real-time via webhooks from the SMS provider. It may take a few seconds for the status to change from `SENT` to `DELIVERED`. You can find more about the endpoint in the [Get Invitation Status API Reference](/api-reference/review-booster/the-status-of-a-review-invitation). ## Configuring Your Sender Name The expeditor name is what customers see as the sender when they receive the SMS instead of a phone number. A well-chosen sender name improves message open rates and trust. To ensure that SMS messages reach customers correctly and comply with carrier requirements, follow these rules: * **Do not use first names**: Avoid personal names like "Léo", "Laurence", "Cédric" * **Do not use generic names**: Avoid generic terms like "Info", "SMS", "The Mayor" * **Use only alphanumeric characters**: Letters and numbers only, no special characters or emojis * **Maximum 11 characters**: Keep your sender name concise * **Only one space allowed**: Multiple spaces are not permitted We recommend using your brand or business name while following these rules. For example: "CafeParisien" or "MyStore" Use the POST endpoint to configure the sender name: ```bash theme={null} POST /review_booster/expeditor ``` You can find more about the endpoint in the [Set Expeditor Name API Reference](/api-reference/review-booster/set-the-expeditor-name-of-a-business). Get the configured sender name for a business: ```bash theme={null} GET /review_booster/expeditor?business_id={business_id} ``` You can find more about the endpoint in the [Get Expeditor Name API Reference](/api-reference/review-booster/the-expeditor-name-of-a-business). ## Working with SMS Templates Templates allow you to create reusable, personalized messages for your review invitations. They support dynamic placeholders that are automatically filled when sending invitations. ### Available Placeholders You can use the following placeholders in your templates: * **`${client_name}`**: The customer's name (from `target_name` parameter) * **`${business_name}`**: Your business name from Partoo * **`${url}`**: The unique review link (required in every template) The `${url}` placeholder is mandatory in every template. Templates without it will be rejected. ### Template Constraints * **Maximum 250 characters**: Excluding placeholders (placeholders don't count toward the limit) * **Must include `${url}`**: The review link placeholder is required * **One template per user**: Each user has a single template that applies to all their businesses Retrieve your existing template (a default template is created if none exists): ```bash theme={null} GET /review_booster/template ``` If no template exists, the system automatically creates a default template for you. You can find more about the endpoint in the [Get Template API Reference](/api-reference/review-booster/template-for-a-user). Customize your template with your own message: ```bash theme={null} PUT /review_booster/template ``` Example template: ``` Hello ${client_name}, thank you for visiting ${business_name}! We'd love your feedback: ${url} ``` You can find more about the endpoint in the [Update Template API Reference](/api-reference/review-booster/update-the-template-of-a-user). # Security and API Key Usage Source: https://developers.partoo.co/guides/api/resources/settings/security_and_api_key_usage Keep your Partoo API integration secure by handling keys and environments correctly. ## Overview Accessing the API Key Management page requires specific rights. Contact your Partoo Account Manager if you need this permission. **API keys can be configured to have full access to your organization's data!** Treat them like passwords — never: * share them publicly, * expose them in frontend or client-side code, * or commit them to version control. To protect your organization's data, it's essential to handle API keys properly and understand environment limitations. ## Why You Should Never Use API Keys in Frontend Code Exposing your API key in frontend or client-side code (e.g., in a browser or mobile app) can lead to unauthorized access. API keys grant full access to your data, and if they are exposed publicly, they can be extracted and misused by malicious users. Additionally, direct API calls from a frontend will fail due to **CORS restrictions** — the Partoo API is designed to be accessed only from secure, server-side environments. ## Using API Keys With Restricted Permissions It is usually a good idea to follow the *Principle of Least Privilege* when creating API keys. This means granting only the permissions necessary for the task at hand. For example, if an API key is only used for updating business information, there's no need for permissions related to, for example, replying to reviews, or managing users. In order for an API Key to use restricted permissions, it must have the value `has_restricted_permissions` set to `true`. If this value is `false`, any API key will have the exact same permissions as the creating user. You can set the `has_restricted_permissions` value when creating the API key, or when updating an existing API key. ### In the Partoo App Go to **Settings > Integrations > API Keys**. From here, you can click either the "Create" button in the top-right corner, or the "Edit" button found inside the drop-down context menu, next to an existing key, to access the API key form. API Keys settings page in the Partoo app Click **Create API Key** and fill in a **Label**, an optional **Description**, and an optional **Expiry Date** for your key. API key creation form showing label, description, and expiry date fields Enable the **Restricted Permissions** toggle, then select the specific permissions you want to grant to this key. Restricted permissions toggle and permission selector in the API key creation form Click **Save** to create the key. ### Using the REST API When creating or updating an API key, include the `has_restricted_permissions` and `permissions` fields in the request body. For more information, see: * [**POST** `/api_keys` - Create API Key](/api-reference/apikeys/create-api-key) * [**PUT** `/api_keys/{api_key_id}` - Update API Key](/api-reference/apikeys/update-api-key) ## How to Use API Keys Securely Create API keys with only the permissions needed for their specific, intended usage. (See [Using API Keys With Restricted Permissions](#using-api-keys-with-restricted-permissions) above for more details.) Use environment variables or a secret manager to avoid hardcoding your API key. Do not include your API key in any public frontend source (JavaScript, mobile apps, etc.). For frontend use cases, route requests through your own backend. The backend appends the API key securely and forwards the request to the Partoo API. Please refer to our [How to Display Partoo Data](/guides/api/guides/display-data) guide for a detailed example. # Activation Source: https://developers.partoo.co/guides/api/resources/settings/sso/activation Steps to enable SSO functionality for your team Contact your Partoo representative to request SSO feature activation. The SSO feature plan will be enabled for your organization. Once enabled, go to the SSO configuration page in the Partoo app: `https://app.partoo.co/settings/integrations/sso/{sso-type}` Replace `{sso-type}` with either `oidc` or `saml`, depending on your chosen protocol. Provide your tech team with the relevant configuration URLs from the setup page: * **SAML**: ACS URL, Metadata URL * **OIDC**: Redirect URL # Configure your Identity Provider Source: https://developers.partoo.co/guides/api/resources/settings/sso/configuration-idp Set up a Partoo application in your Identity Provider using SAML or OIDC Use the configuration values provided in the Partoo app’s SSO setup page. * **ACS URL**: `https://app.partoo.co/api/v2/saml/{identifier}/acs` * **Entity ID**: `https://app.partoo.co/api/v2/saml/{identifier}/metadata/` * **Attribute mapping**: `email` or `urn:oid:0.9.2342.19200300.100.1.3` * \[Optional] Allowed callback URL: same as ACS URL * **Redirect URL**: `https://app.partoo.co/connection?sso_alias={identifier}` Replace `{identifier}` with the unique ID provided in the SSO configuration page — it could be a UUID or a custom name. Depending on your protocol, export your Identity Provider’s configuration: * For **SAML**: Export the XML metadata file. * For **OIDC**: Copy the `.well-known` URL. # Configure SSO within Partoo Source: https://developers.partoo.co/guides/api/resources/settings/sso/configuration-partoo Connect your Identity Provider to Partoo using metadata or .well-known URL Go to the SSO setup page in the Partoo app. Example: `https://app.partoo.co/settings/integrations/sso/{sso-type}` SSO configuration interface in the Partoo application Use one of the following methods: Click on **Prefill** and upload your `metadata.xml` file. Or manually enter: * Entity ID * Single Sign-On URL * X.509 certificate Webhook listing in the Partoo interface Click on **Prefill** and enter your `.well-known` URL. Or manually enter: * Issuer * Authorization endpoint * Token endpoint * JWKS URI You’ll also need to enter your `client_id` and optionally a `client_secret`. Webhook listing in the Partoo interface * Technical contact email * Expiration date of your certificate or configuration Toggle the activation switch at the top-right of the page. If you forget this step, the connection won't be usable even if correctly configured. You cannot configure both SAML and OIDC single sign-on (SSO) simultaneously. Please choose either SAML or OIDC for your SSO setup to avoid configuration conflicts. Webhook listing in the Partoo interface # FAQ Source: https://developers.partoo.co/guides/api/resources/settings/sso/faq Frequently asked questions about using Single Sign-On with Partoo No. SSO in Partoo does not create users automatically. You must first create users manually using the Partoo interface or via the API before they can log in with SSO. Use the [User Creation API](/api-reference/users/create-user) to automate onboarding. When creating a user via the API, set: ```json theme={null} { "sso_only": true, "send_invitation": false, "password": null } ``` This disables email invitations and login by password, allowing SSO login only. Partoo sends an email to the technical contact before your SAML certificate expires. Follow the instructions in the email to upload a new certificate in the app or send it to the support address provided. An expired certificate can prevent users from logging in. Yes. You can continue to use other login methods like Google if configured in your Identity Provider. SSO is just one of the supported login methods. Contact your Customer Success Manager or reach out via our [Technical Support](https://support.partoo.co) channel for guidance. # Overview Source: https://developers.partoo.co/guides/api/resources/settings/sso/index Understand the key concepts and supported SSO connection types with Partoo Single Sign-On (SSO) allows your users to access multiple applications with a single set of credentials. ## What is SSO? SSO (Single Sign-On) is an authentication mechanism that enables users to access Partoo directly through your company portal, without manually entering their Partoo login credentials. SSO is only available for users who already have an existing Partoo account. It does not automatically create accounts. ## Supported protocols Partoo supports two widely-used SSO protocols that are compatible with most identity providers (IdPs) such as Google, Okta, or Azure AD: * **SAML 2.0** * **OpenID Connect (OIDC)** with the PKCE flow Choose the protocol that matches your identity provider's capabilities. SSO configuration interface in the Partoo application # Test SSO Source: https://developers.partoo.co/guides/api/resources/settings/sso/test-production Verify your SSO setup and complete the integration for end-users Try the login endpoints to validate your setup: * **SAML**: `https://app.partoo.co/api/v2/saml/{identifier}/login` * **OIDC**: `https://app.partoo.co/api/v2/oidc/{identifier}/login` If authentication succeeds, you’ll be redirected to Partoo. In the app, check the SSO setup page for advice if errors occur. You can use sandbox environments to test before going live. Provide your users a direct link to connect via SSO. Once everything is tested, consider the connection ready for full production use. # API Source: https://developers.partoo.co/guides/api/resources/settings/webhooks/api Manage webhook subscriptions programmatically using the API." You can use our beta API to manage webhook subscriptions. This feature is in beta and subject to change. Only required for PROVIDER users acting on behalf of customers. ```bash cURL theme={null} curl -X POST \ --url https://api.partoo.co/v2/webhooks \ --header 'Content-Type: application/json' \ --header 'x-APIKey: ' \ -d '{ "items": [ { "url": "https://your-server.com/webhook", "event_type": "business_created" } ] }' ``` ```json Success theme={null} { "items": [ { "id": 12345, "event_type": "business_created", "url": "https://your-server.com/webhook", "org_id": 1, "created_at": "2024-11-27T16:10:44.929678Z", "updated_at": "2024-11-27T16:10:44.929678Z" } ] } ``` # Events Source: https://developers.partoo.co/guides/api/resources/settings/webhooks/events Explore all available webhook events and their payloads. Each webhook event includes a `type` and a `payload` object. Triggered when a business is created in Partoo. See full details Triggered when business data is modified. See full details Triggered when a business is removed. See full details Triggered when a new message is added to a conversation. See full details Triggered when the status or content of a message changes. See full details Triggered when a new lead is captured in Partoo. See full details Triggered when a new review is submitted. See full details Triggered when the content or status of a review is modified. See full details Triggered when a reply is added to a review. See full details Triggered when the content of a review reply is modified. See full details Triggered when a reply to a review is removed. See full details Triggered when a reply is added to a review pushed through a [custom review partner](/guides/api/resources/reviews/retrieve-reviews#custom-review-partners). Set up by Partoo, not subscribable from the webhooks page. See full details Triggered when a reply to a custom-partner review is edited. See full details Triggered when a reply to a custom-partner review is removed. See full details Triggered when a recipient opts out of survey emails. See full details # Overview Source: https://developers.partoo.co/guides/api/resources/settings/webhooks/index Learn how to set up and secure webhooks, and explore available event triggers. Webhooks let you receive real-time notifications when specific events occur.\ When triggered, a webhook sends event data to the URL you’ve configured. Webhooks are scoped by `org_id`—you’ll only receive events for businesses linked to the same organization. Learn how to configure webhooks in the app or via API. Secure your webhooks with signature verification and shared secrets. See all supported webhook events and their API payloads. See all supported webhook events and their API payloads. # Security Source: https://developers.partoo.co/guides/api/resources/settings/webhooks/security Secure your webhook integrations with signature verification and shared secrets. Security is critical when dealing with automated event notifications. ## Digital Signature Verification All webhook requests include a digital signature using the ED25519 algorithm. The signature is provided in the following HTTP header: ```http theme={null} X-Partoo-Signature-v1: BASE64_SIGNATURE ``` To verify: 1. Base64 decode the signature 2. Recalculate the hash of the payload 3. Use our public key to validate the signature Use separate keys for production and sandbox environments. Use different public keys depending on the environment: ```plaintext theme={null} -----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEA0G9ciHL6XZQXuWq6W4dFLvwNEPWgcdtQgEVlBIwZWBQ= -----END PUBLIC KEY----- ``` ```plaintext theme={null} -----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEALsyvX2yVnG3ZKRIFfEvYk2nkzanoNgAqBSqdeNub4sM= -----END PUBLIC KEY----- ``` ## Code Examples Here are sample snippets to help you implement signature verification: ```python Python theme={null} from base64 import b64decode import binascii from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import ed25519 # load public key from filesystem, you may adapt depending on your secret management framework public_key = serialization.load_pem_public_key(open("/var/secrets/partoo.pub.pem")) def validate_signature(request): if (signature:=request.headers.get("X-Partoo-Signature-v1")) is None: raise ValueError("Missing signature") # don't trust your inputs # will raise a subclass of ValueError if format is invalid decoded_signature = b64decode(signature, validate=True) # validate payload's signature try: public_key.verify(decoded_signature, request.body.encode()) except Exception as e: raise ValueError("Invalid signature") from e ``` ```javascript JavaScript theme={null} const fs = require('fs'); const crypto = require('crypto'); // Load public key from filesystem const publicKey = fs.readFileSync('/var/secrets/partoo.pub.pem', 'utf8'); function validateSignature(request) { const signature = request.headers['x-partoo-signature-v1']; if (!signature) { throw new Error('Missing signature'); } // Decode the base64 signature let decodedSignature; try { decodedSignature = Buffer.from(signature, 'base64'); } catch (err) { throw new Error('Invalid signature format'); } // Verify the payload's signature const payload = request.body; if (!crypto.verify(null, Buffer.from(payload), publicKey, decodedSignature)) { throw new Error('Invalid signature'); } } ``` ```go Go theme={null} package main import ( "crypto/ed25519" "encoding/base64" "encoding/pem" "errors" "io/ioutil" "net/http" ) func loadPublicKey(path string) (ed25519.PublicKey, error) { keyData, err := ioutil.ReadFile(path) if err != nil { return nil, err } block, _ := pem.Decode(keyData) if block == nil { return nil, errors.New("failed to parse PEM block") } publicKey := ed25519.PublicKey(block.Bytes[12:]) // Skip ASN.1 header return publicKey, nil } func validateSignature(r *http.Request, payload []byte) error { signature := r.Header.Get("X-Partoo-Signature-v1") if signature == "" { return errors.New("missing signature") } // Decode base64 signature decodedSignature, err := base64.StdEncoding.DecodeString(signature) if err != nil { return errors.New("invalid signature format") } // Load public key publicKey, err := loadPublicKey("/var/secrets/partoo.pub.pem") if err != nil { return err } // Verify signature if !ed25519.Verify(publicKey, payload, decodedSignature) { return errors.New("invalid signature") } return nil } ``` ```java Java theme={null} import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.security.KeyFactory; import java.security.PublicKey; import java.security.Signature; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; public class WebhookValidator { private static PublicKey loadPublicKey(String path) throws Exception { String keyPem = new String(Files.readAllBytes(Paths.get(path))); keyPem = keyPem.replace("-----BEGIN PUBLIC KEY-----", "") .replace("-----END PUBLIC KEY-----", "") .replaceAll("\\s", ""); byte[] keyBytes = Base64.getDecoder().decode(keyPem); X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("Ed25519"); return keyFactory.generatePublic(spec); } public static void validateSignature(String signatureHeader, String payload) throws Exception { if (signatureHeader == null || signatureHeader.isEmpty()) { throw new IllegalArgumentException("Missing signature"); } // Decode base64 signature byte[] decodedSignature; try { decodedSignature = Base64.getDecoder().decode(signatureHeader); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("Invalid signature format", e); } // Load public key PublicKey publicKey = loadPublicKey("/var/secrets/partoo.pub.pem"); // Verify signature Signature sig = Signature.getInstance("Ed25519"); sig.initVerify(publicKey); sig.update(payload.getBytes()); if (!sig.verify(decodedSignature)) { throw new SecurityException("Invalid signature"); } } } ``` ```php PHP theme={null} header('X-Partoo-Signature-v1'); if (!$signature) { throw new Exception('Missing signature'); } // Decode base64 signature $decodedSignature = base64_decode($signature, true); if ($decodedSignature === false) { throw new Exception('Invalid signature format'); } // Load public key from filesystem $publicKeyPem = file_get_contents('/var/secrets/partoo.pub.pem'); $publicKey = openssl_pkey_get_public($publicKeyPem); if (!$publicKey) { throw new Exception('Failed to load public key'); } // Verify signature using Ed25519 $keyDetails = openssl_pkey_get_details($publicKey); $publicKeyRaw = $keyDetails['key']; // For Ed25519 verification with PHP, you may need sodium extension if (!function_exists('sodium_crypto_sign_verify_detached')) { throw new Exception('Sodium extension required for Ed25519 verification'); } // Extract raw public key (skip ASN.1 header) $rawKey = substr(base64_decode( str_replace(['-----BEGIN PUBLIC KEY-----', '-----END PUBLIC KEY-----', "\n"], '', $publicKeyPem) ), 12); if (!sodium_crypto_sign_verify_detached($decodedSignature, $payload, $rawKey)) { throw new Exception('Invalid signature'); } } ?> ``` ## Shared Secret in URL You may include a shared secret in your webhook URL: Examples: ```bash theme={null} https://my.integration.io/webhooks/partoo/9fa91de19/business_update https://my.integration.io/webhooks/partoo/business_update?key=9fa91de19 ``` # Setup Source: https://developers.partoo.co/guides/api/resources/settings/webhooks/setup How to configure and subscribe to webhooks in Partoo. You can set up webhooks either via the **Partoo interface** or through the **API**. From the app interface: Webhook listing in the Partoo interface 1. Go to **Settings > Integrations > Webhooks** 2. Click **Create** to add a new webhook 3. Provide a valid **callback URL** and choose one or more **event types** 4. Optionally, test the endpoint before saving Webhook creation form with callback URL and event type You can register up to **5 webhooks per event type** per organization. Each must use a unique URL — all registered URLs receive the event. The same URL can be reused across different event types. Each event type is independent. Choose only the ones you need. You must supply a valid HTTPS URL that can receive `POST` requests. You can register up to **5 webhooks per event type** per organization. Each must use a unique URL — all registered URLs receive the event. The same URL can be reused across different event types. Exceeding the limit returns a `400` error. We use the `org_id` to ensure events go to the right organization. Required fields: * `url` – your endpoint * `org_id` – your organization ID * `event_type` – the event to subscribe to Optional fields: * `custom_headers` – custom HTTP headers to forward with each webhook request (e.g. for authentication). Keys must start with `X-` and must not use the `X-Partoo` prefix. Maximum 5 headers. Key max length: 128 characters. Value max length: 512 characters. The following characters are forbidden in header keys: space, `(`, `)`, `<`, `>`, `@`, `,`, `;`, `:`, `\`, `"`, `/`, `[`, `]`, `?`, `=`, `{`, `}`. You must return a `200 OK` response to acknowledge receipt. If your server returns a `5xx` error, we retry the request up to 5 times with exponential backoff.\ For other errors (4xx), no retries occur. # Partoo MCP Server Source: https://developers.partoo.co/guides/mcp/overview Connect AI assistants to the Partoo platform using the Model Context Protocol (MCP) — manage business listings, reviews, messages, posts, and analytics through natural language. ## Overview The **Partoo MCP Server** implements the [Model Context Protocol](https://modelcontextprotocol.io), a standard that lets AI assistants call external tools. It exposes the Partoo API as a set of ready-to-use tools so that LLMs like Claude can search businesses, reply to reviews, send messages, publish posts, and query analytics — all without writing a single line of integration code. The MCP server is stateless and proxies every request to the Partoo REST API on your behalf. No data is stored server-side. ## Authentication Every MCP request must include your Partoo API key in the `x-APIKey` header. The server forwards it to the Partoo API and never stores it. Your Partoo API key. Refer to the [API Keys guide](/guides/api/resources/settings/security_and_api_key_usage) to generate one. Keep your API key secret. Do not commit it to source control — use your LLM client's secret/environment variable mechanism instead. ## Environments | Environment | MCP Server URL | | - | - | | **Production** | `https://mcp.partoo.co` | | **Sandbox** | `https://mcp.sandbox.partoo.co` | Start with the Sandbox URL to test your setup safely before switching to Production. ## Connect with your LLM The Partoo MCP Server uses the **Streamable HTTP** transport (a single `POST /` endpoint). All major MCP-compatible clients support this transport. Replace `YOUR_API_KEY` with your actual Partoo API key in the snippets below. Claude Desktop connects to the Partoo server through a small helper called [`mcp-remote`](https://www.npmjs.com/package/mcp-remote). You don't need to install it by hand — the configuration below launches it automatically with `npx`. **Why the helper is needed.** Claude Desktop's built-in "Add custom connector" option only signs in with OAuth — it logs you into a service through a browser pop-up and has no place to enter an API key. The Partoo server doesn't use OAuth; it authenticates with your API key sent in the `x-APIKey` header. Since the connector screen can't attach that header, the built-in option can't reach Partoo. `mcp-remote` fills the gap: it sits between Claude Desktop and the Partoo server and adds your API key to every request. **Before you start**, install [Node.js](https://nodejs.org) (the LTS version is fine). This provides the `npx` command used in the configuration. To confirm it's installed, open a terminal and run `node --version` and `npx --version` — both should print a version number. Then edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows): ```json claude_desktop_config.json theme={null} { "mcpServers": { "partoo": { "command": "npx", "args": [ "-y", "mcp-remote", "https://mcp.partoo.co", "--header", "x-APIKey:${PARTOO_API_KEY}" ], "env": { "PARTOO_API_KEY": "YOUR_API_KEY" } } } } ``` Replace `YOUR_API_KEY` with your actual Partoo API key — leave `PARTOO_API_KEY` untouched. `PARTOO_API_KEY` is the name of the environment variable referenced by `${PARTOO_API_KEY}` in the arguments; only the value next to it (`YOUR_API_KEY`) should be edited. Do not put a space in the `--header` value. `mcp-remote` splits header arguments on spaces, so reference the key via the `PARTOO_API_KEY` environment variable (set in `env`) using `${PARTOO_API_KEY}` with no space. Fully quit and reopen Claude Desktop after saving (closing the window is not enough). The Partoo tools will then appear in the tool picker. **Option 1 — CLI (recommended)** Run the following command to register the server. Use `--scope project` to limit it to the current repository, or `--scope user` to make it available globally. ```bash Production theme={null} claude mcp add --transport http --scope user partoo https://mcp.partoo.co \ --header "x-APIKey: YOUR_API_KEY" ``` ```bash Sandbox theme={null} claude mcp add --transport http --scope user partoo https://mcp.sandbox.partoo.co \ --header "x-APIKey: YOUR_API_KEY" ``` **Option 2 — Manual config** Add the server directly to `~/.claude/settings.json` (user-level) or `.claude/settings.json` at the root of your project (project-level): ```json settings.json theme={null} { "mcpServers": { "partoo": { "type": "http", "url": "https://mcp.partoo.co", "headers": { "x-APIKey": "YOUR_API_KEY" } } } } ``` Prefer `--scope project` (or the project-level config file) when working in a single repository. Add `.claude/settings.json` to `.gitignore` if it contains your API key directly. Create or edit `.cursor/mcp.json` at the root of your project (or `~/.cursor/mcp.json` for a global config): ```json .cursor/mcp.json theme={null} { "mcpServers": { "partoo": { "url": "https://mcp.partoo.co", "headers": { "x-APIKey": "YOUR_API_KEY" } } } } ``` Reload the Cursor window after saving. Any MCP client that supports Streamable HTTP can connect to the Partoo MCP Server. Use the following values: | Setting | Value | | - | - | | Transport | Streamable HTTP | | URL | `https://mcp.partoo.co` | | Header name | `x-APIKey` | | Header value | Your Partoo API key | Refer to your client's documentation for the exact configuration format. ## Available tools The server exposes **14 tools** across 5 groups. See the [Tools Reference](/guides/mcp/tools) for the full parameter list. | Group | Tools | | - | - | | **Businesses** | `search_businesses`, `get_business`, `update_business` | | **Reviews** | `search_reviews`, `reply_to_review`, `get_review_metrics` | | **Messages** | `list_conversations`, `send_message`, `list_messages` | | **Posts** | `create_post`, `search_posts` | | **Analytics** | `get_profile_metrics`, `get_profile_keywords` | # MCP Tools Reference Source: https://developers.partoo.co/guides/mcp/tools Complete reference for all 14 tools exposed by the Partoo MCP Server, grouped by category with parameter details. The Partoo MCP Server exposes **14 tools** across 5 groups. All tools require an `x-APIKey` header — see the [Overview](/guides/mcp/overview) for connection instructions. *** ## Businesses Search, retrieve, and update business listings managed in Partoo. ### `search_businesses` Search for businesses with optional filters. Supports fuzzy matching across city, zip code, and business name. Fuzzy search term matched against city, zip code, and business name. Exact business name filter. Filter by city. Filter by postal code. Filter by country. ISO 3166 alpha-2 code (e.g. `FR`, `GB`). Filter by business status. One of: `open`, `closed`, `opening_soon`, `temporarily_closed`. Filter by internal business code. Filter by organisation ID. Available to `PROVIDER` users only. Page number (1–100). Results per page (1–100). Field to sort by. Prefix with `-` for descending order (e.g. `-name`). *** ### `get_business` Fetch the full detail of a single business. Business ID, or `c-{code}` to look up by store code. *** ### `update_business` Update one or more fields of an existing business. Only the fields you provide are changed. Business ID, or `c-{code}` to look up by store code. **Identity** Business display name. Internal store code. Group IDs to assign to the business. Category IDs. At least one must be provided if this field is set. National business registration number. **Status** One of: `open`, `closed`, `temporarily_closed`. Planned opening date. Format: `YYYY-MM-DD`. **Address** Street address line 1. Street address line 2. City. Postal code. Region or state. ISO 3166 alpha-2 country code (e.g. `FR`, `GB`). Latitude in decimal degrees. Longitude in decimal degrees. **Online presence** Business website URL. Facebook page URL. Twitter / X profile URL. **Descriptions** Short description. Maximum 80 characters. Long description. Maximum 750 characters. **Hours & contacts** Regular opening hours. Provide all 7 days. Exceptional opening periods (holidays, special events). Contact entries (phone numbers, email addresses, etc.). Photo assignments for the business profile. *** ## Reviews Search reviews, post replies, and retrieve review analytics. ### `search_reviews` Search for customer reviews across one or more businesses with optional filters. Comma-separated list of business IDs to filter by. Comma-separated list of review platforms. Accepted values: `google_my_business`, `facebook`, `tripadvisor`. Comma-separated list of review states. Accepted values: `treated`, `not_treated`, `deleted`. Comma-separated keywords to search for in review content. Return reviews updated on or after this date. ISO 8601 format. Return reviews updated on or before this date. ISO 8601 format. Set to `true` to return only reviews without text content. Set to `true` to return only untagged reviews. Page number (1–100). Results per page (1–100). Sort field. Accepted values: `update_date`, `-update_date`. *** ### `reply_to_review` Post a public reply to a customer review. ID of the review to reply to. Text content of the reply. *** ### `get_review_metrics` Retrieve aggregated review analytics such as average rating, rating distribution, reply rate, and trends. Comma-separated list of metrics to retrieve. Accepted values: `average_rating`, `rating_distribution`, `reviews_count`, `reply_time`, `reply_means`, `rank`. Comma-separated list of dimensions to group by. Accepted values: `day`, `week`, `month`, `year`, `business`, `group`, `tag`. Comma-separated list of business IDs to filter by. Start of the date range. ISO 8601 format. End of the date range. ISO 8601 format. Field to sort by. Prefix with `-` for descending order. Page number. Results per page. *** ## Messages List conversations and send messages through Partoo's messaging platform. ### `list_conversations` List messaging conversations, optionally filtered by business. Comma-separated list of business IDs to filter by. Results per page (1–100). Pagination cursor returned by the previous response. *** ### `send_message` Send a text message in an existing conversation. ID of the conversation to send the message to. Text content of the message. *** ### `list_messages` List messages within a conversation. ID of the conversation. Results per page (1–100). Pagination cursor returned by the previous response. *** ## Posts Create and search social posts published to Google, Facebook, and Instagram. ### `create_post` Create and publish a post to one or more platforms. Supports news, events, and offers with optional CTAs and scheduling. IDs of the businesses to publish the post for. Platforms to publish to. Accepted values: `google_my_business`, `facebook`, `instagram`. Type of post. One of: `news`, `event`, `offer`. Main text content of the post. Post title. URL of the image to attach to the post. Call-to-action button type. One of: `book`, `order`, `shop`, `learn_more`, `sign_up`, `call`, `no_cta`. URL linked from the call-to-action button. Post start date/time in ISO 8601 format. Uses the business's local timezone. Post end date/time in ISO 8601 format. Uses the business's local timezone. Set to `true` to save as a draft instead of publishing immediately. *** ### `search_posts` Search posts published across Google, Facebook, Instagram, and Store Locator. Comma-separated list of business IDs to filter by. Filter by a substring match on the post description. Comma-separated list of post states. Accepted values: `live`, `to_configure`, `pending`, `scheduled`, `error`, `expired`, `to_validate`. Filter by post type. One of: `standard`, `event`, `offer`, `alert`. Return posts starting on or after this date/time. ISO 8601 format. Return posts ending on or before this date/time. ISO 8601 format. Page number (1–100). Results per page (1–100). *** ## Analytics Query Google Business Profile metrics and search keyword data. ### `get_profile_metrics` Retrieve Google Business Profile performance metrics such as impressions, direction requests, call clicks, and website clicks. Comma-separated list of metrics to retrieve. Accepted values: `business_impressions_desktop_maps`, `business_impressions_desktop_search`, `business_impressions_mobile_maps`, `business_impressions_mobile_search`, `business_direction_requests`, `call_clicks`, `website_clicks`. Comma-separated list of dimensions to group by. Accepted values: `business`, `day`, `week`, `month`, `year`. Comma-separated list of business IDs to filter by. Fuzzy search term matched against city, zip code, and business name. Filter by city. Start of the date range. ISO 8601 format. End of the date range. ISO 8601 format. Field to sort by. Prefix with `-` for descending order. Page number. Results per page (max 500). *** ### `get_profile_keywords` Retrieve Google search keywords that drove traffic to business profiles. Comma-separated list of metrics to retrieve. Accepted values: `count`, `threshold`. Comma-separated list of dimensions to group by. Accepted values: `business`, `keyword`, `month`, `year`, `branded`. Comma-separated list of business IDs to filter by. Set to `true` to return only branded keywords, `false` for discovery keywords only. Start of the date range. ISO 8601 format. End of the date range. ISO 8601 format. Field to sort by. Prefix with `-` for descending order. Page number. Results per page (max 500). # Tutorial Source: https://developers.partoo.co/guides/sdk/getting-started/quickstart Learn how to integrate Partoo into your website using the JavaScript SDK to display embedded views and manage user sessions. ## Introduction Use the Partoo JavaScript SDK to embed Partoo views into your website via an iframe. The SDK provides utilities to configure, initialize, and control the embedded experience. The SDK dynamically inserts an iframe and returns a helper instance that you can use to authenticate users and navigate pages. ## Environments Partoo offers two environments: * **Sandbox**: For development and testing\ URL: `https://static.sandbox.partoo.co/jssdk/partoo.js` * **Production**: For live deployment\ URL: `https://static.partoo.co/jssdk/partoo.js` # Integration Steps Include the SDK in your HTML ``: ```html theme={null} ``` This exposes a global `Partoo` object for use in your scripts. Before rendering any views, generate a **connection token** for your authenticated user. Refer to the authentication [API documentation](/api-reference/connection-tokens/generate-connection-token#generate-connection-token) for details on generating this token. Add a target `
` where the Partoo iframe will load: ```html theme={null}
``` Do not use `partoo-iframe` as the container ID—it's reserved internally. Use the SDK to create and display the iframe: ```javascript theme={null} const connectionToken = 'YOUR_CONNECTION_TOKEN'; const options = { startPage: 'presenceManagement', displayIntercom: false, // Optional: default is true displayAddButton: false // Optional: default is true }; const partooPage = Partoo.init('your-container-id', options); partooPage.login(connectionToken); ``` This logs in the user and displays the `startPage`. To load a business edit view directly, pass both `startPage` and `selectedBusinessId`: ```javascript theme={null} const options = { startPage: 'business', selectedBusinessId: '62ba00000000000000000000', displayIntercom: false, displayAddButton: false }; const partooPage = Partoo.init('your-container-id', options); partooPage.login(connectionToken); ``` # Page Navigation Use the `partooPage` instance to programmatically navigate: ```javascript theme={null} partooPage.navigate('businesses'); // Go to the businesses list partooPage.back(); // Go back to the previous page partooPage.forward(); // Go forward to the next page partooPage.destroy(); // Remove the iframe ``` # Next Steps Thanks to this quick tutorial, you learned how to display your first Partoo app view thanks to the JS SDK. To build a production ready integration, you might want to check the [Integration Guide](#). # Authenticate Source: https://developers.partoo.co/guides/sdk/guides/authenticate ## Authenticate a User with the Connection Token Most Partoo App views require an authenticated user. This is done using a short-lived, one-time **connection token** generated through the Partoo REST API. ### Authentication Flow To authenticate a user: 1. Your backend requests a connection token from Partoo using the REST API. 2. You embed the token in the page rendered to your frontend. 3. Your frontend initializes the SDK and logs in the user using the token. ```javascript theme={null} partooPage.login('your-connection-token'); ``` This login call triggers the following: * The SDK sends the connection token to the Partoo login endpoint. * Partoo validates the token and returns a JWT. * The user is considered authenticated until the JWT expires. Connection tokens are **single-use** and **short-lived**. You must implement a system to regenerate a new token whenever a user accesses a protected view after the previous token expires. ```mermaid theme={null} sequenceDiagram participant Client participant YourServer as Your server participant Partoo as Partoo server Client->>YourServer: 1. Request Partoo page using JS SDK YourServer->>Partoo: 2. Generate connection token for user Partoo->>YourServer: 3. Return connection token YourServer->>Client: 4. Serve HTML with SDK and token Client->>Partoo: 5. partooPage.login('token') Partoo->>Client: 6. Return JWT to keep session active ``` Design your backend to detect expired JWTs and automatically request new connection tokens before loading protected views. # Events & Callbacks Source: https://developers.partoo.co/guides/sdk/guides/events-callbacks ## Capturing Partoo App Events with Callbacks You can configure callbacks to be triggered when specific events occur in the embedded Partoo App. These callbacks allow your integration to respond to user actions such as creating a business, clicking links, or encountering errors. Some callbacks are **blocking** (they prevent the default behavior unless explicitly continued), while others are **non-blocking** (the Partoo App continues its normal flow). *** ## Setting Up a Callback Use the `.on(eventId, callback)` method from the Partoo page instance to register an event listener. ### Syntax ```javascript theme={null} partooPage.on(eventId, callbackFunction); ``` * `eventId` — a string identifier for the event * `callbackFunction` — a JavaScript function that receives an event-specific `data` object ### Example ```javascript theme={null} const subscribeCallback = (data) => { console.log('User subscribed to:', data); }; partooPage.on('subscribe', subscribeCallback); ``` *** ## Supported Callback Events ### `subscribe` Triggered when a user clicks **Subscribe**. ```json theme={null} { "productName": "presence_management", "businesses": [ { "id": "5a2ab4edb12ff67cba1b7e1b", "org_id": 709, "name": "SCEP du Caire" } ] } ``` *** ### `open_business` Triggered when a user opens a business page. ```javascript theme={null} // data = "5a2ab4edb12ff67cba1b7e1b" ``` *** ### `business_created` Triggered after a business is created and saved. This callback does **not** block redirection to the business edit page. ```javascript theme={null} // data = "5a2ab4edb12ff67cba1b7e1b" ``` *** ### `business_additional_info_updated` Triggered when additional info is updated and saved. This is a non-blocking callback. ```javascript theme={null} // data = { ... } ``` *** ### `business_address_updated` Triggered when address information is updated and saved. This is a non-blocking callback. ```javascript theme={null} // data = { ... } ``` *** ### `business_contact_updated` Triggered when contact details are updated. This is a non-blocking callback. ```javascript theme={null} // data = { ... } ``` *** ### `business_description_updated` Triggered when a business description is updated. This is a non-blocking callback. ```javascript theme={null} // data = { ... } ``` *** ### `business_open_hours_updated` Triggered when open hours are updated and saved. This is a non-blocking callback. ```javascript theme={null} // data = { ... } ``` *** ### `error` Triggered when a rendering error occurs (e.g. HTTP 400, 403, 404, 500). ```javascript theme={null} // data = 403 // HTTP status code ``` *** ### `no_business_click` Triggered when the **No Business** button is clicked. ```javascript theme={null} partooPage.on('no_business_click', () => { // Handle click event }); ``` *** ### `no_eligible_business_click` Triggered when the **No Eligible Business** button is clicked. ```javascript theme={null} partooPage.on('no_eligible_business_click', () => { // Handle click event }); ``` *** ### `pm_view_go_to_edit_click` Triggered when a user clicks **Edit** in the Presence Management view. ```javascript theme={null} partooPage.on('pm_view_go_to_edit_click', () => { // Handle redirection to business edit }); ``` *** ### `pm_view_go_to_partner_connection_click` Triggered when a user clicks a link to go to **Partner Connection** from Presence Management. ```javascript theme={null} partooPage.on('pm_view_go_to_partner_connection_click', () => { // Handle redirection to connection view }); ``` *** Use callback data to sync user actions with your backend, trigger alerts, or log analytics events in real-time. # Integration Source: https://developers.partoo.co/guides/sdk/guides/integration Learn how to integrate and navigate between Partoo pages inside your application using the SDK. ## Navigate Between Partoo App Pages Use the `navigate`, `back`, and `forward` methods on the `partooPage` instance to control user navigation between embedded Partoo views. ### Basic Navigation Methods ```javascript theme={null} // Navigate to a specific page partooPage.navigate('reviewManagement', seedData, pageOptions); // Navigate back to the previous page partooPage.back(); // Navigate forward to the next page partooPage.forward(); ``` * `routeName` (string): Required route identifier for the page * `seedData` (object): Optional data used to preload or configure the view * `pageOptions` (object): Optional parameters such as businessId, status, etc. 📖 For the **complete list of supported routes**, see [Supported Routes](/guides/sdk/references/supported-routes). ## View Integration Examples Each example assumes you’ve already initialized the SDK and authenticated the user: ```javascript theme={null} const partooPage = Partoo.init('partoo-container', {}); partooPage.login('yourConnectionToken'); ``` ### Business List Page ```javascript theme={null} partooPage.navigate('businesses'); ``` **Available callbacks**: `subscribe`, `open_business` ### Business Edit Page ```javascript theme={null} partooPage.navigate('business', null, { businessId: 'yourBusinessId' }); ``` **Available callbacks**: ❌ None ### Add Business Page ```javascript theme={null} partooPage.navigate('add'); ``` **Available callbacks**: `business_created` ### Analytics Page ```javascript theme={null} partooPage.navigate('analytics'); ``` **Available callbacks**: ❌ None ### Presence Management Page ```javascript theme={null} partooPage.navigate('presenceManagement'); ``` **Available callbacks**: * `pm_view_go_to_edit_click` * `pm_view_go_to_partner_connection_click` ### Posts Page ```javascript theme={null} partooPage.navigate('posts', null, { status: 'unpublished' }); ``` Valid `status` values: `all`, `published`, `unpublished`, `pending`\ **Available callbacks**: ❌ None ### Review Management Page ```javascript theme={null} partooPage.navigate('reviewManagement', null, { status: 'not-treated' }); ``` Valid `status` values: `live`, `treated`, `not-treated`, `deleted`\ **Available callbacks**: ❌ None ### Auto Reply Settings Page - for reviews without comments ```javascript theme={null} partooPage.navigate('reviewAutoReplyWithoutComments'); ``` **Available callbacks**: ❌ None ### Auto Reply Settings Page - for reviews with comments ```javascript theme={null} partooPage.navigate('reviewAutoReplyWithComments'); ``` **Available callbacks**: ❌ None ### Review Analytics Page ```javascript theme={null} partooPage.navigate('reviewAnalytics'); ``` **Available callbacks**: ❌ None ### Review Analysis Page ```javascript theme={null} partooPage.navigate('reviewAnalysis'); ``` **Available callbacks**: ❌ None ### Review Booster Page ```javascript theme={null} partooPage.navigate('reviewBooster'); ``` **Available callbacks**: ❌ None ### Partner Connections Page ```javascript theme={null} partooPage.navigate('partnerConnections'); ``` **Available callbacks**: ❌ None ### Messaging Page ```javascript theme={null} partooPage.navigate('messaging'); ``` **Available callbacks**: ❌ None ### Bulk Update Page ```javascript theme={null} partooPage.navigate('bulkUpdate'); ``` **Available callbacks**: ❌ None ### Conversation Starters Page ```javascript theme={null} partooPage.navigate('conversationStarters'); ``` **Available callbacks**: ❌ None ### Google Verification Page ```javascript theme={null} partooPage.navigate('googleVerification'); ``` **Available callbacks**: ❌ None ### WhatsApp Settings Page ```javascript theme={null} partooPage.navigate('whatsappSettings'); ``` **Available callbacks**: ❌ None # Partoo SDK Reference Source: https://developers.partoo.co/guides/sdk/references/reference ## Global `Partoo` The `Partoo` object is available globally when you include the JS SDK in your page: ```html theme={null} ``` This object exposes the `Partoo.init()` method to embed and manage Partoo views inside an iframe. *** ## `Partoo.init(divId, options)` Initializes a Partoo App instance by inserting an iframe into the specified DOM element. ### Parameters ID of the target `
` where the iframe will be rendered. Optional configuration object. See [Options](/guides/sdk/references/reference#options) for details. ### Returns Returns a `Page` object used to interact with the embedded iframe. ```javascript theme={null} const partooPage = Partoo.init('your-container-id', options); ``` *** ## Page The `Page` object returned by `Partoo.init()` provides methods for navigation, authentication, event handling, and more. ```javascript theme={null} const partooPage = Partoo.init('divId'); ``` ### Methods #### `setOptions(options)` Updates the iframe configuration after initialization. Options object to update the view behavior. See [Options](/guides/sdk/references/reference#options). *** #### `login(connectionToken)` Authenticates the user and navigates to the defined `startPage`. One-time connection token generated from the Partoo API. ```javascript theme={null} partooPage.login('your-connection-token'); ``` *** #### `navigate(route, seedData, additionalParams)` Navigates to a specific page in the Partoo App. Target page identifier. See [Supported Pages](/guides/sdk/references/supported-routes). Deprecated. Page-specific parameters (e.g. `businessId`, `status`, etc.). ```javascript theme={null} partooPage.navigate('business', null, { businessId: 'abc123' }); ``` *** #### `back()` Navigates to the previous page in iframe history. ```javascript theme={null} partooPage.back(); ``` *** #### `forward()` Navigates forward in iframe history (opposite of `back()`). ```javascript theme={null} partooPage.forward(); ``` *** #### `on(eventId, callback)` Registers a callback function for a specific event triggered in the Partoo App. ID of the event. See [Available callback events](/guides/sdk/guides/events-callbacks). Function triggered when the event occurs. Receives event-specific `data`. ```javascript theme={null} partooPage.on('subscribe', function(data) { console.log('Subscription data:', data); }); ``` *** ## Options The `options` parameter is accepted by both `Partoo.init()` and `setOptions()`: ```javascript theme={null} const options = { startPage: 'businesses', displayIntercom: false, selectedBusinessId: 'abc123', // more options... }; const partooPage = Partoo.init('partoo-container', options); partooPage.setOptions(options); ``` ### Configuration Fields | Parameter | Type | Default | Description | | - | - | - | - | | `startPage` | `string` | `businesses` | Initial route displayed after login | | `startPageAnchorParam` | `string` | `null` | Anchor parameter appended to login URL | | `displayIntercom` | `boolean` | `true` | Show or hide the Intercom help widget | | `displayAddButton` | `boolean` | `true` | Show or hide the add business button on the top banner | | `displayPresenceManagementDownload` | `boolean` | `true` | Show or hide the download button on Presence Management view | | `displayBusinessModalFilters` | `boolean` | `true` | Show or hide business filters on relevant pages (e.g. Posts, Reviews, Messaging) | | `displayVerificationRequiredButton` | `boolean` | `false` | Display a verification banner in business list and business pages | | `selectedBusinessId` | `string` | `null` | Preselect a business on applicable views (e.g. Review, Messaging). Use `null` to reset | Use `setOptions()` if you need to update configuration dynamically after initialization. # Supported Routes Source: https://developers.partoo.co/guides/sdk/references/supported-routes Reference of all available Partoo routes, including parameters, view descriptions, and authentication requirements. ## Overview This page provides the **complete list of available Partoo pages (routes)** that can be embedded via the SDK.\ Each entry details its : * the **route name** to pass to `navigate()` * supported **seedData** and **pageOptions** * a **description of the view** * whether **authentication is required** ## Supported Pages and Routes | Route Name | seedData | pageOptions | View Description | Auth | | - | - | - | - | - | | `businesses` | `null` | `null` | List of user’s businesses | ✅ | | `business` | `null` | `{ businessId: string }` | Edit view of a specific business | ✅ | | `add` | `null` | `null` | Add a new business | ✅ | | `analytics` | `null` | `null` | Analytics dashboard | ✅ | | `presenceManagement` | `null` | `null` | Presence Management view | ✅ | | `posts` | `null` | `{ status: string }` | Posts management view | ✅ | | `reviewManagement` | `null` | `{ status: string }` | Review management interface | ✅ | | `reviewAutoReplyWithoutComments` | `null` | `null` | Auto reply settings page for reviews w/o comments | ✅ | | `reviewAutoReplyWithComments` | `null` | `null` | Auto reply settings page for reviews with comments | ✅ | | `reviewAnalytics` | `null` | `null` | Review analytics dashboard | ✅ | | `reviewAnalysis` | `null` | `null` | Review analysis dashboard | ✅ | | `competitorsAnalytics` | `null` | `null` | Competitor analytics dashboard | ✅ | | `competitorsAnalysis` | `null` | `null` | Competitor analysis dashboard | ✅ | | `reviewBooster` | `null` | `null` | Review booster tool | ✅ | | `partnerConnections` | `null` | `null` | Google & Facebook connection settings | ✅ | | `messaging` | `null` | `null` | Messaging dashboard | ✅ | | `bulkUpdate` | `null` | `null` | Bulk update view | ✅ | | `conversationStarters` | `null` | `null` | Conversation starter settings | ✅ | | `googleVerification` | `null` | `null` | Google verification setup | ✅ | | `whatsappSettings` | `null` | `null` | WhatsApp settings | ✅ | | `widgetSettings` | `null` | `null` | Widget settings page | ✅ | # Welcome Source: https://developers.partoo.co/index Build with the Partoo API v2. Manage locations, reviews, messaging, and more — securely and at scale.
Partoo Partoo # Build with the Partoo API

Manage locations, reviews, messaging, and more — securely and at scale.

Explore API use cases

Make your first API call in minutes. Explore the advanced features available in Partoo. Integrate and scale using our API and SDKs. Connect any messaging channel to Partoo. Manage SSO via our API. Manage Webhooks via our API.

Explore core concepts

Understand Providers, Organizations, Groups, Businesses, and Users. See who can read and write which resources. Errors, rate limits, security, and retry strategies. Workflow for adding, updating, or removing users.

Quick links

Browse the different endpoints and try requests. See what’s new and what changed.
# How to get help? Source: https://developers.partoo.co/misc/help/how-to-get-help Learn the proper way to ask for help via email, including escalation paths and the required information for faster resolution. ## Facing an Issue? Here’s What to Do If you encounter an issue or have a question while using Partoo, follow these steps in order. The list is organized from **fastest to slowest resolution time**. Use the search bar in this documentation to find answers to your question. The documentation is updated regularly to cover the most common issues and questions. Before reaching out, verify that our services are fully operational by visiting our [status page](https://status.partoo.co/).\ Updates about potential incidents or ongoing resolutions are posted there in real time. For support via email, contact us at: [api@partoo.fr](mailto:api@partoo.fr) Make sure to include all the required information listed below to help us respond quickly and accurately. ## Urgent Issues An **urgent issue** means: * It occurs **only** in the `production` **environment**. * Your integration or bot was working fine previously. * Suddenly, something stopped working and this directly impacts your users. Also, we kindly ask you **not to send meeting requests** right away. Our policy is to first exchange details by email to make sure we fully understand the situation without overloading our developers. If, after these exchanges, the issue is still blocking, we will of course be happy to schedule a meeting. For urgent issues, **send your report directly** to [api@partoo.fr](mailto:api@partoo.fr) and copy your Account Manager. ## Information Required in Your Request When sending an email, please include the following information that help us quickly understand and resolve your request : * Your **entity name** (client name) * Give your **full name** (first name + last name) * If you are reporting a problem for another person, please mention the **first name, last name and email address** of the person concerned by the problem. * Your **subscription type** (e.g., pm, rm, rb, bm) * A **clear explanation of your problem or need** * **Impacted feature(s)** (e.g., post creation, edit business information, etc.) * **Steps to reproduce** the issue * The **expected behavior** vs. the **actual behavior** * Any **error messages or logs** * The **API calls performed**, with: * Endpoint(s) * Payload (if applicable) * Timestamps of the requests * The **environment** where the issue occurs (`production`, `sandbox`) * Relevant **screenshots** or **screen recordings** The more complete your request, the faster we can provide you with an accurate solution. # Example of a Perfect Support Email Below is a model email you can adapt to your case. It contains all the required details. ```text theme={null} To: api@partoo.fr CC: Subject: [Acme Corp] Issue with Post Creation Feature in Production Hello Partoo Support Team, I am experiencing an issue with the **Post Creation feature**. - **Entity name**: Acme Corp - **Affected person**: John Doe - john.doe@acme.com - **Subscription type**: pm - **Environment**: Production **Problem description** Until this morning, everything was working fine. Starting from 09:30 CET, our requests to create posts started failing. **Steps to reproduce** 1. Send a POST request to `/posts/create` with a valid payload. 2. Observe the response. **Expected behavior** The request should return `200 OK` and confirm post creation. **Actual behavior** We receive a `400 Bad Request` error. **Error details** { "error": { "authorization": "Operation not allowed" } } **API calls performed** - Endpoint: `POST /posts` - Timestamp: 2025-09-10T09:30:02Z - Payload: { "business_search": { "business__in": [ [ "5409c35a97bbc544d8e26737", "595badaef348ab6b3530033f", "59d53302b12ff6429f262639" ] ], ... (rest of payload) } } I have attached screenshots of the failed requests for reference. Could you please investigate and advise on the root cause? Since this impacts our production environment, I would appreciate an urgent resolution. Thank you, John Doe Lead Developer – Acme Corp john.doe@acme.com ``` By following this structure, your request will be processed more efficiently and resolved faster. # OpenAPI file Source: https://developers.partoo.co/misc/help/openapi-download View or download the Partoo REST API OpenAPI specification file in YAML format. ## Access the OpenAPI Specification The OpenAPI specification defines all endpoints, parameters, request/response schemas, and authentication methods for the Partoo REST API. You can view the specification in an API tool or download it for offline use. Here's how: * **Download the complete YAML file** * **Import it into an OpenAPI-compatible tool** (Postman, Insomnia, Swagger UI, etc.) * **Use it to automatically generate an API client (SDK)** *** ## Download the OpenAPI File (YAML) Download the full bundled OpenAPI specification: Download OpenAPI Specification (YAML) The file downloads as a `.yaml` document and is ready to use in compatible API tools. *** ## View the Specification in an API Tool After downloading the file, you can import it into your preferred API tool. ### Example: Import into Postman Launch the Postman application. Click **Import**, then select the `openapi-bundled.yaml` file. Postman automatically creates a collection containing all available API endpoints. You can see all API routes listed in your workspace. *** ## Generate an API Client Automatically You can use the OpenAPI specification to generate a typed SDK client. ### Example with OpenAPI Generator (CLI) ```bash theme={null} openapi-generator-cli generate \ -i openapi-bundled.yaml \ -g typescript-axios \ -o ./partoo-api-client ``` This command generates a TypeScript client based on the official API definition. Always use the latest version of the OpenAPI file to ensure compatibility with recently added or updated endpoints. *** ## Need Help? If you encounter issues while importing or generating a client: * Verify that the YAML file is valid * Ensure your OpenAPI tool supports the specification version * Check the official documentation of the tool you are using The OpenAPI specification reflects the current version of the Partoo REST API.