Hootsuite CRM Webhooks API

### Webhook authentication When receiving data from Inbox 2.0, we provide two authentication options. Both mechanisms are in place so that you can make sure the request originates from Inbox 2.0. #### Shared secret If you choose the shared secret authentication method, a secret will be generated for you. This secret allows you to calculate the signature to verify that the call originated from Inbox 2.0. With this mechanism, every single request from Inbox 2.0 contains the `X-Hootsuite-Signature` header. Here's an example of a request: ```shell curl -X POST https://my-webhook-url \ -H 'content-type : application/json' \ -H 'accept: application/json' \ -H 'X-Hootsuite-Signature: e6f93239a06e46ae9654fc9ad2fb4e1cc4eb213830a0d94e711570c047e43c57' \ -d '{ "version": 2, "contactProfile": { "id": "a7a20053-9c54-11eb-a89f-47717a44c639" }, "contactAttributes": [ {"attribute": "email", "value": "fj@example.com"} ] }' ``` The signature is generated using the `HMAC-SHA256` algorithm with the shared secret and the request body. Use your secret to calculate the signature and compare with the given signature. Both the secret key you received and the signature are encoded as hexadecimal strings. Make sure to convert the shared secret from its hexadecimal representation to its binary format before using it. Most languages come with libraries out of the box to verify this signature. For example, here's how it looks in JavaScript: ```javascript const crypto = require("crypto"); const secret = "..."; // do not share! const expectedSignature = request.headers["X-Hootsuite-Signature"]; const actualSignature = crypto .createHmac("sha256", Buffer.from(secret, "hex")) .update(request.body, "utf-8") .digest("hex"); if (actualSignature !== expectedSignature) { throw new createError.Unauthorized("X-Hootsuite-Signature wrong"); } console.log(JSON.parse(request.body).email); ``` #### OAuth If your endpoints support OAuth2, you can configure your client credentials, a Token URL, and, optionally, a Scope in Inbox 2.0. We use the OAuth2 Client Credentials flow to authenticate against your CRM. The Token URL is the endpoint where we can authenticate with these credentials and retrieve an access token. To do the actual lookup, write back, or notification requests, we use the token in the Authorization Header to authenticate.

Documentation

Specifications

Other Resources

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/hootsuite-crm-webhooks-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

hootsuite-crm-webhooks-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Inbox 2.0 API Reference CRM Webhooks API
  description: Inbox 2.0 API Reference
  version: v1
  x-logo:
    url: static/hootsuite-logo.png
  contact:
    email: dev.support@hootsuite.com
  license:
    name: Hootsuite Developer Terms and API License Agreement
    url: https://hootsuite.com/legal/dev-api-terms
servers:
- url: https://platform.hootsuite.com
  description: Inbox 2.0 production server
security:
- bearer-token: []
tags:
- name: crm_webhooks
  x-displayName: Webhooks
  description: "### Webhook authentication\n\nWhen receiving data from Inbox 2.0, we provide two authentication options. Both mechanisms are in place so that you can make sure the request originates from Inbox 2.0.\n\n#### Shared secret\n\nIf you choose the shared secret authentication method, a secret will be generated for you. This secret allows you to calculate the signature to verify that the call originated from Inbox 2.0. With this mechanism, every single request from Inbox 2.0 contains the `X-Hootsuite-Signature` header. Here's an example of a request:\n\n```shell\ncurl -X POST https://my-webhook-url \\\n  -H 'content-type : application/json' \\\n  -H 'accept: application/json' \\\n  -H 'X-Hootsuite-Signature: e6f93239a06e46ae9654fc9ad2fb4e1cc4eb213830a0d94e711570c047e43c57' \\\n  -d '{\n        \"version\": 2,\n        \"contactProfile\": {\n          \"id\": \"a7a20053-9c54-11eb-a89f-47717a44c639\"\n        },\n        \"contactAttributes\": [\n          {\"attribute\": \"email\", \"value\": \"fj@example.com\"}\n        ]\n      }'\n```\n\nThe signature is generated using the `HMAC-SHA256` algorithm with the shared secret and the request body. \nUse your secret to calculate the signature and compare with the given signature. \nBoth the secret key you received and the signature are encoded as hexadecimal strings. \nMake sure to convert the shared secret from its hexadecimal representation to its binary format before using it. \nMost languages come with libraries out of the box to verify this signature. \nFor example, here's how it looks in JavaScript:\n\n```javascript\nconst crypto = require(\"crypto\");\nconst secret = \"...\"; // do not share!\nconst expectedSignature = request.headers[\"X-Hootsuite-Signature\"];\nconst actualSignature = crypto\n    .createHmac(\"sha256\", Buffer.from(secret, \"hex\"))\n    .update(request.body, \"utf-8\")\n    .digest(\"hex\");\nif (actualSignature !== expectedSignature) {\n    throw new createError.Unauthorized(\"X-Hootsuite-Signature wrong\");\n}\nconsole.log(JSON.parse(request.body).email);\n```\n\n#### OAuth\n\nIf your endpoints support OAuth2, you can configure your client credentials, a Token URL, and, optionally, a Scope in Inbox 2.0.\n\nWe use the OAuth2 Client Credentials flow to authenticate against your CRM. The Token URL is the endpoint where we can authenticate with these credentials and retrieve an access token. To do the actual lookup, write back, or notification requests, we use the token in the Authorization Header to authenticate.\n"
paths: {}
webhooks:
  crm-attribute-lookup:
    post:
      summary: Contact attribute lookup
      description: "Inbox 2.0 CRM integration allows you to pull customer contact data from CRMs or other internal business applications into Inbox 2.0. To integrate your CRM with Inbox 2.0, you need to provide an HTTPS endpoint for lookups.\n\n### Create contact attributes\n\n1.  In Inbox 2.0, go to `Admin settings`, expand `Agent Workspace`, select `Contact attributes`, and then select `Add attribute`.\n2.  Select `Managed by CRM`. The CRM is the source of truth for these attributes. After they are imported into Inbox 2.0, they only change when the value changes in the CRM.\n3.  Identify lookup attributes by selecting `Use as lookup attribute`. These are used by the CRM to find a customer's data. For example, if you want to find a customer by email address, create an attribute called \"Email\" and designate it as a lookup. When the request is made from Inbox 2.0 to your CRM, the lookup fields are included in the request body.\n4.  In the `Unique identifier` box, enter an alias for the lookup attribute. This is used to map the response from your system to the attribute.\n\n### Configure integration URL\n\nTo pull data from your CRM into Inbox 2.0, you need to implement a POST endpoint that accepts a JSON request and returns a JSON response. The request contains the lookup attributes, and the response should contain the contact data from your CRM.\n\nAfter the endpoint is implemented, configure it as the lookup URL:\n\n1.  Go to `Admin settings`.\n2.  Expand `Integration and APIs`.\n3.  Select `CRM`.\n\n### Handle the request\n\nWhen the endpoint in your system is ready and configured in Inbox 2.0, and one or more lookup attributes have been identified, you can make a request via the `Lookup` button in the conversation view.\nThis will trigger the CRM attribute lookup event.\n\nAfter you've done the lookup in your system, pass attributes back to Inbox 2.0 as a JSON response. The keys in the attributes object correspond to the aliases that were previously added in Inbox 2.0. If a CRM managed attribute is missing from the object or the key has a `null` value, its value is deleted in Inbox 2.0. Inbox 2.0 expects the response in this format:\n\n```json\n{\n    \"autoConfirm\": false,\n    \"contactAttributes\": [\n        {\"attribute\": \"email\", \"value\": \"fj@example.com\"},\n        {\"attribute\": \"id\", \"value\": \"98765432\"},\n        {\"attribute\": \"first_name\", \"value\": \"Fred\"},\n        {\"attribute\": \"last_name\", \"value\": \"Jones\"},\n        {\"attribute\": \"last_order_number\", null}\n    ]\n}\n```\n\n### Asynchronous Response\nYou can also return a 200 OK back without a body and call our REST api to send back the result of the lookup request.\nCall the following REST endpoint:\n\n```bash\ncurl --request PUT 'https://platform.hootsuite.com/inbox/v2/contact/{contactProfileId}/contact-attributes' \\\n--header 'content-type: application/json' \\\n--header 'Authorization: BEARER <token>' \\\n--data-raw '{\n              \"autoConfirm\": false,\n              \"contactAttributes\": [\n                {\"attribute\": \"email\", \"value\": \"fj@example.com\"},\n                {\"attribute\": \"id\", \"value\": \"98765432\"},\n                {\"attribute\": \"first_name\", \"value\": \"Fred\"},\n                {\"attribute\": \"last_name\", \"value\": \"Jones\"},\n                {\"attribute\": \"last_order_number\", null}\n              ]\n            }'\n```\n\n### Confirm your attributes\n\nThe CRM attributes sent back in the response must be confirmed before they are saved in Inbox 2.0. There are two ways to do that:\n\n  -   Select the `Confirm` button when you see the CRM attributes displayed in Inbox 2.0 after the lookup request.\n  -   Add an `autoConfirm` field to the response.\n\nThe `autoConfirm` field tells Inbox 2.0 to automatically save the attributes without having to use the `Confirm` button.\n"
      operationId: crmAttributeLookup
      security:
      - Oauth2ClientCredentials: []
      - SharedSecret: []
      tags:
      - crm_webhooks
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: JSON object containing the lookup attributes
              additionalProperties:
                type: string
            example:
              my-customer-id: '123'
      responses:
        '200':
          description: 'Returns the attributes to be updated in Inbox 2.0.

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CrmLookupAttributesResponse'
        4xx:
          description: 'Lookup failed

            '
        5xx:
          description: 'Lookup failed

            '
  crm-error-notifications:
    post:
      summary: Contact attribute lookup error notifications event
      description: "When attribute update validation errors occur, Inbox 2.0 sends a request to the configured notification URL.\n\n### Configure notification URL\n\nWhen you send your CRM managed contact attributes, Inbox 2.0 does some validation on the response. To see validation errors, we've provided a way to send notifications from Inbox 2.0 to your system. You need to provide a POST endpoint that accepts a JSON request body. Configure a notification URL on the same screen where you configured a lookup URL:\n\n  1.  Go to `Admin settings`.\n  2.  Expand `Integration and APIs`.\n  3.  Select `CRM`.\n\n### Handle the request\n\nWhen validation errors occur, Inbox 2.0 sends a request to the configured notification URL. A request [looks like this](#operation/crmAttributeLookupValidationErrorNotification).\n\nThe request contains these two fields:\n\n  -   eventType\n  -   messages: an array of explicit error messages\n\nThe following are the event types that can be sent by Inbox 2.0.\n\n| Event type        | Description                                                 |\n|-------------------|-------------------------------------------------------------|\n| DATA_IMPORT_ERROR | Error occurred while pulling data from the CRM to Inbox 2.0. |\n\nThe response to this request can be a 204. Inbox 2.0 does not expect anything in the response body.\n"
      operationId: crmContactAttributeLookupErrorNotification
      security:
      - Oauth2ClientCredentials: []
      - SharedSecret: []
      tags:
      - crm_webhooks
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CrmErrorNotificationsRequest'
      responses:
        '204':
          description: 'To indicate that the notification was received successfully

            '
        4xx:
          description: 'Could not process notification

            '
        5xx:
          description: 'Could not process notification

            '
  crm-write-back:
    post:
      summary: 'CRM write back event

        '
      description: "# CRM write back\n\nYou can be notified whenever a conversation has taken place in Inbox 2.0 (`CONVERSATION_RESOLVED`) or an agent has set a current conversation to Pending (`CONVERSATION_SET_TO_PENDING`). This allows you to save conversation details to your existing CRM system. Other use cases include triggering CSAT surveys, case creation, and expanded customer insights from social media profiles.\n\n### Configure write back URL\n\nTo push data from Inbox 2.0 into your CRM, you need to implement a POST endpoint that accepts a JSON request and returns a JSON response. The request contains write back payload, and the response's status code represents your ability to parse the payload and the CRM's ability to ingest the data.\n\nConfigure the endpoint as the `Write Back URL`:\n\n  1.  Go to `Admin settings`.\n  2.  Expand `Integration and APIs`.\n  3.  Select `CRM`.\n\n### Handle the request\n\nWhen the endpoint in your system is ready and configured in Inbox 2.0, and relevant events occur within Inbox 2.0, requests are sent to the configured endpoint. All decoded write back payloads have the following fields:\n\n  -   `type`: A string that defines what kind of write back request is being processed. Used to suggest the structure of the `data` field.\n  -   `version`: A number designating the version of the `type` of request. Used to mark changes to the `data` field structure.\n  -   `idempotencyKey`: A string that uniquely identifies each event to write back. Used to help ensure that each request is processed only once.\n  -   `data`: An object that contains structured data for the specific `type` of write back. For example, a `CONVERSATION_RESOLVED` type event has fields such as `medium`, `channel`, `messages`\\*, `notes`, `topics`, `contactProfile`\\*, `attributes`\\*, and `agent`, among others.\n\n  `*` Applies to all mediums except Twitter. Twitter handle, tweets, and direct message transcripts, and Twitter medium contact attributes (Twitter name, number of followers, etc.), are not sent in the payload, to conform to Twitter's data use policies.\n\n### CONVERSATION_RESOLVED and CONVERSATION_SET_TO_PENDING events\n\nEvents with a type of either `CONVERSATION_RESOLVED` or `CONVERSATION_SET_TO_PENDING` have the structure defined.\n\n### Write back retry\n\nIf the write back request times out or the endpoint returns a non-success (2XX) status code, Inbox 2.0 retries with exponential backoffs. The requests are sent again with a delay of 1, 2, 4, 8, 16, and 32 hours after each retry (a total of 6 requests), as long as the request does not succeed. If the request still has not succeeded after 6 requests, we store the failed request details for future reference. We recommend that you inspect the endpoint logs regularly to ensure that write back requests are properly processed the first time. To distinguish between unique events, each request is given an Idempotency key.\n\n### Idempotency key\n\nThe write back requests from Inbox 2.0 make use of an Idempotency key, which allows the write back endpoint to ensure it processes each request once. This key helps when requests are sent multiple times during the retry schedule, so the endpoint can handle requests in an idempotent way. The key is unique per request.\n"
      operationId: crmWriteBack
      security:
      - Oauth2ClientCredentials: []
      - SharedSecret: []
      tags:
      - crm_webhooks
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CrmWriteBackRequest'
      responses:
        2xx:
          description: 'The response status code represents your ability to parse the payload and the CRM''s ability to ingest the data.

            '
        4xx:
          description: 'The response status code represents your ability to parse the payload and the CRM''s ability to ingest the data. Any non-2XX response status code will be retried.

            '
        5xx:
          description: 'The response status code represents your ability to parse the payload and the CRM''s ability to ingest the data. Any non-2XX response status code will be retried.

            '
components:
  schemas:
    CrmWriteBackRequest:
      type: object
      description: The request contains write back payload.
      properties:
        timestamp:
          type: string
          format: date-time
          example: '2022-03-28T09:43:26.635984618Z'
        idempotencyKey:
          type: string
          description: A string that uniquely identifies each event. Used to help ensure that each request is processed only once.
          example: 6ebc6a78-d9e9-48be-b172-51eda40b7af8
        version:
          type: integer
          description: 'A number designating the version of the `type` of request. Used to mark changes to the `data` field structure.

            '
          example: 1
        type:
          type: string
          enum:
          - CONVERSATION_RESOLVED
          - CONVERSATION_SET_TO_PENDING
          example: CONVERSATION_RESOLVED
        data:
          type: object
          properties:
            conversation:
              type: object
              properties:
                id:
                  type: string
                  example: 0ad42eef-a806-11eb-9642-f1ceb2f21def
                createdAt:
                  type: string
                  format: date-time
                  example: '2022-03-28T09:42:27.004817183Z'
                previousStatus:
                  type: string
                  enum:
                  - new
                  - pending
                  - resolved
                  example: resolved
                currentStatus:
                  type: string
                  enum:
                  - new
                  - pending
                  - resolved
                  example: resolved
            medium:
              type: object
              properties:
                id:
                  type: string
                  example: fb
            channel:
              type: object
              properties:
                id:
                  type: string
                  example: 0-02534c5ac04-000-261ad914
                name:
                  type: string
                  example: Inbox 2.0 support channel
            agent:
              type: object
              properties:
                id:
                  type: string
                  example: '11599'
                firstName:
                  type: string
                  example: John
                lastName:
                  type: string
                  example: Smith
                email:
                  type: string
                  example: john.smith@hootsuite.com
            contactProfile:
              type: object
              properties:
                id:
                  type: string
                  example: 693ed54b-a426-11eb-9363-cffd945b4b2f
                mediumContactProfileId:
                  type: string
                  example: bb7b0f8f00cc989b97f0725b
                primaryIdentifier:
                  type: string
                  example: John Smith
                secondaryIdentifier:
                  type: string
                  example: '+32439487192'
                pictureUrl:
                  type: string
                  example: https://example.com/my-picture.png
            statusUpdatedReason:
              type: string
              example: 5fd023f6-2e66-11eb-be07-092841b0717d - Response Not Required
            statusUpdatedComment:
              type: string
              example: not a question
            messages:
              type: array
              items:
                type: object
                properties:
                  id:
                    type: string
                  direction:
                    type: string
                    enum:
                    - INBOUND
                    - OUTBOUND
                  text:
                    type: string
                example:
                - id: 0ad20c0d-a806-11eb-9642-f799d0e531de
                  direction: INBOUND
                  text: I have a question
                - id: 10664516-a806-11eb-9642-fbd9d431bd78
                  direction: OUTBOUND
                  text: How can I help you?
            contactAttributes:
              type: array
              items:
                type: object
                properties:
                  attribute:
                    type: string
                    example: null
                  value:
                    type: string
                  source:
                    type: string
                    enum:
                    - AGENT
                    - MEDIUM
                    - CRM_CONFIRMED
              example:
              - attribute: company
                value: My company
                source: AGENT
              - attribute: fb-profile-name
                value: John Smith
                source: MEDIUM
              - attribute: fb-profile-image
                value: https://image.com/sticky/default_profile_images/default_profile_normal.png
                source: MEDIUM
              - attribute: email
                value: john.smith@hootsuite.com
                source: CRM_CONFIRMED
              - attribute: first_name
                value: John
                source: CRM_CONFIRMED
              - attribute: last_name
                value: Smith
                source: CRM_CONFIRMED
              - attribute: company
                value: Hootsuite
                source: CRM_CONFIRMED
            notes:
              type: array
              items:
                type: object
                properties:
                  id:
                    type: string
                  text:
                    type: string
                  creationUser:
                    type: string
                  creationTimestamp:
                    type: string
                    format: date-time
              example:
              - id: 8080a48b-3c70-11e1-8931-1e8999d73ad2
                text: Here's a note on the conversation!
                creationUser: 0-019bd608cfc-001-0c6a2f5b
                creationTimestamp: '2018-06-28T00:17:09+00:00'
            topics:
              type: array
              items:
                type: object
                properties:
                  id:
                    type: string
                  name:
                    type: string
              example:
              - id: aa33389d-8a6a-11e8-b0d0-61f12b43ea29
                name: Redeem Rewards
              - id: ee089cc2-8a6a-11e8-b0d0-942d249592dc
                name: Account Rewards
    CrmErrorNotificationsRequest:
      type: object
      properties:
        timestamp:
          type: string
          format: date-time
        version:
          type: integer
          example: 2
        eventType:
          type: string
          enum:
          - DATA_IMPORT_ERROR
        messages:
          type: array
          description: an array of explicit error messages
          items:
            type: string
          example:
          - testMessage1 key:testKey1 value:testValue1
          - testMessage2 key:testKey2 value:testValue2
    CrmLookupAttributesResponse:
      type: object
      properties:
        autoConfirm:
          type: boolean
          description: 'The `autoConfirm` field tells Inbox 2.0 to automatically save the attributes without having to use the `Confirm` button.

            '
        contactAttributes:
          type: array
          description: Array of JSON objects containing the lookup attributes
          items:
            additionalProperties:
              type: object
              properties:
                attribute:
                  type: string
                value:
                  type: string
      example:
        autoConfirm: true
        contactAttributes:
        - attribute: email
          value: fj@example.com
        - attribute: id
          value: '98765432'
        - attribute: first_name
          value: Fred
        - attribute: last_name
          value: Jones
        - attribute: last_order_number
          value: null
  securitySchemes:
    bearer-token:
      type: http
      scheme: bearer
    basic-auth:
      type: http
      scheme: basic
    Oauth2ClientCredentials:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: TO_BE_CONFIGURED_IN_INBOX_2_0
          scopes:
            some_scope: TO_BE_CONFIGURED_IN_INBOX_2_0
    SharedSecret:
      type: apiKey
      in: header
      name: X-Hootsuite-Signature
x-provenance:
  generated: '2026-08-13'
  method: searched
  source: https://apidocs.hootsuite.com/docs/api/inbox/openapi/openapi.yaml
  note: Verbatim first-party OpenAPI 3.1 for the Hootsuite Inbox 2.0 API (formerly Sparkcentral), linked as service-desc for anchor https://platform.hootsuite.com/inbox/v1/ in Hootsuite's RFC 9727 API catalog at https://www.hootsuite.com/.well-known/api-catalog.
  ownership: servers[] https://platform.hootsuite.com, contact dev.support@hootsuite.com, license "Hootsuite Developer Terms and API License Agreement" - Hootsuite's own contract.
x-tagGroups:
- name: General
  tags:
  - rest-api-authentication
- name: CRM API
  tags:
  - crm_introduction
  - crm_webhooks
  - crm_rest_api
- name: Virtual Agent API
  tags:
  - vai_introduction
  - vai_webhooks
  - vai_rest_api
- name: Real-time metrics API
  tags:
  - real_time_metrics_introduction
  - real_time_metrics_rest_api
- name: User Presence API
  tags:
  - user_presence_introduction
  - user_presence_rest_api
- name: Queue API
  tags:
  - queue_introduction
  - queue_rest_api
- name: Proactive messaging API
  tags:
  - proactive_messaging_introduction
  - proactive_messaging_rest_api
- name: Messenger SDK
  tags:
  - messenger_introduction
  - messenger_web_sdk