Shepherd Veterinary Software Message API

The Message API from Shepherd Veterinary Software — 2 operation(s) for message.

Operations 2

POST /pav2/open-api-messages Retrieves {OpenApiMessageController.Message} resources that match the specified… #
POST /pav2/open-api-messages/write Inserts a new {OpenApiMessageController.Message} resource. #

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/shepherd-vet:shepherd-vet-message-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

shepherd-vet-message-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  version: v1
  title: Shepherd Open API (v2.248.0.39) Message API
  description: 'Production Base URL: https://open-api.shepherd.vet/pav2/


    Production App URL: https://app.shepherd.vet/


    Production Documentation URL: https://app.shepherd.vet/swagger/


    Sandbox Base URL: https://demo-open-api.shepherd.vet/pav2/


    Sandbox App URL: https://demo.shepherd.vet/


    Sandbox Documentation URL: https://demo.shepherd.vet/swagger


    Authorization: The integration is authorized by providing two headers in the API call


    X-Integration-Private-Key - this contains the private key from your credentials

    X-Integration-Public-Key - this contains the public key from your credentials


    Additionally, for all requests other than Clinic, the X-Clinic-Id header must be provided with the value of the clinic entity id for which you are running the API requests. You can get the entity id by calling the Clinic endpoint. If authorization fails, the request returns HTTP status 401 and the response body is one of the messages below. Missing X-Integration-Public-Key header - the public key header is absent from the request. Missing X-Integration-Private-Key header - the private key header is absent from the request. Missing X-Clinic-Id header - the clinic identifier header is absent, and the endpoint is clinic scoped. Incorrect API keys provided - both key headers were supplied, but the public key matches no integration, or the private key is not valid for that integration. Integration not enabled for the provided clinic - the key pair is valid, but the integration is not enabled and active for the clinic supplied in X-Clinic-Id. NEW: Each API call will count against your RPH and RPM limits. Once you exhaust those limits, requests will start returning HTTP status 429. The RPH is set to 12000 and RPM to 800 (subject to change). Where an endpoint supports searchQuery, a query longer than 500 characters may return HTTP status 400 with ERROR_MESSAGES.SEARCH_PHRASE.TOO_LONG, and a query with more than 10 words may return HTTP status 400 with ERROR_MESSAGES.SEARCH_PHRASE.TOO_MANY_PHRASES. NOTE: Since this API is WIP, we would be happy to hear any feedback and to implement additional filtering/sorting options etc. **Endpoints:

    All endpoints are POST requests that accept JSON bodies. The common request properties for all endpoints are:**


    rpp::int - The number of items to return per page. The max is 1000. Defaults to 10. page::int - The page number. Defaults to 1. sort::string - Which field to sort by. Needs to be in "field|order" format, where order is either "asc" or "desc". All top-level properties should be sortable, only some nested-fields work and you should probably not use them until this API reaches production and we settle on which nested-field sortings we will support. Default depends on endpoint, usually "id|asc". embed::string - Comma-separated values for nested-fields you want to fetch (eg. "clientPhones,clientPhones.phoneType" on Client endpoint). If a specific embed is not requested, the response will contain either null or an empty array for that value. No default. dateCreatedFrom::date

    dateCreatedTo::date

    dateUpdatedFrom::date

    dateUpdatedTo::date

    - Date range filters for either the creation date or last update date. - You can pass in either one end or both of them. *


    * Only the date filters listed on an endpoint''s request model are supported; sending another one, or a ''From'' later than its ''To'', returns HTTP status 400. The request responses will come back as a JSON object. The common response properties for all endpoints are:


    embed::string - Lists the embed used in the request. This may sometimes be different from what you sent in, if in the future we add that some embeds get set automatically on certain endpoints

    links::object[] - Always empty, a leftover from the internal framework we use on our web API. Will be removed in the future if possible so do not rely on this

    page::int - Which page was fetched.'
servers:
- url: https://open-api.shepherd.vet
tags:
- name: Message
paths:
  /pav2/open-api-messages:
    post:
      tags:
      - Message
      summary: Retrieves {OpenApiMessageController.Message} resources that match the specified…
      description: 'Example Request

        {

        "clinicIds": "5fa03907-c437-4a56-8cd6-b2bb00ac4232",

        "embed": "messageStatus",

        "isConversationDeleted": false

        }


        Example Response

        {

        "embed": "messageStatus",

        "item": [

        {

        "content": "Reminder for tomorrow''s appointment",

        "conversation": null,

        "conversationId": "d21d5b3e-4cf3-4e0d-915f-b30900be1111",

        "isClientMessage": true,

        "isRead": false,

        "messageStatus": {

        "abrv": "delivered",

        "description": "Message successfully delivered",

        "name": "Delivered",

        "dateCreated": "2025-06-27T10:45:12.000Z",

        "dateUpdated": "2025-06-27T10:45:12.000Z",

        "id": "e5f6d7c8-9012-3abc-4def-b3c200f0abcd",

        "links": [null]

        },

        "messageStatusId": "e5f6d7c8-9012-3abc-4def-b3c200f0abcd",

        "orderNum": 1,

        "sendingScheduledFor": "2025-06-27T11:00:00.000Z",

        "sentByUserFormatted": "Nurse Admin",

        "sentByUserId": "afc01234-abcd-5678-9123-b3c200f01111",

        "dateCreated": "2025-06-27T10:40:00.000Z",

        "dateUpdated": "2025-06-27T10:40:00.000Z",

        "id": "7b6a5c4d-3210-4567-89ab-b3c200f02222",

        "links": [null]

        }

        ],

        "links": [],

        "page": 1,

        "recordsPerPage": 10,

        "searchQuery": null,

        "sort": null,

        "totalRecords": 1

        }

        Multisite Examples

        [

        {

        "title": "Request 1 / Response 1",

        "note": "In this example, messaging is configured at the group level. All messages belong to the group context rather than individual clinics. Returned fields (IDs, status, metadata) reflect the group entity.",

        "request": {},

        "response": {

        "embed": null,

        "item": [

        {

        "content": "Hello from group",

        "conversation": null,

        "conversationId": "b8c2f0c9-3b1c-4fb4-8b5f-1d6b1a4d7a6f",

        "isClientMessage": true,

        "isRead": false,

        "messageStatus": null,

        "messageStatusId": "9a1c5d6e-2f76-4a2c-8d0e-6d3b2bb2f4f1",

        "orderNum": 412,

        "sendingScheduledFor": null,

        "sentByUserFormatted": "Group",

        "sentByUserId": null,

        "dateCreated": "2025-08-20T10:22:31Z",

        "dateUpdated": "2025-08-20T10:22:31Z",

        "id": "7df5a2c4-1f55-4f37-9b0c-2f1f9f7b3c91"

        },

        {

        "content": "Follow-up from group",

        "conversation": null,

        "conversationId": "0c7a2d0c-6b4a-45d2-9b91-2f3f6c9e7c15",

        "isClientMessage": false,

        "isRead": true,

        "messageStatus": null,

        "messageStatusId": "2f3d7a9e-4a1e-4b9a-9e6a-1b2c3d4e5f60",

        "orderNum": 413,

        "sendingScheduledFor": "2025-08-21T09:00:00Z",

        "sentByUserFormatted": "Group",

        "sentByUserId": null,

        "dateCreated": "2025-08-20T11:05:43Z",

        "dateUpdated": "2025-08-20T11:05:43Z",

        "id": "e3b8c7d2-5f41-4d7b-8b97-1a2f3c4d5e6f"

        }

        ],

        "links": [],

        "page": 1,

        "recordsPerPage": 10,

        "searchQuery": null,

        "sort": null,

        "totalRecords": 2

        }

        }

        ]'
      operationId: OpenApiMessageGet
      parameters:
      - name: x-integration-public-key
        in: header
        description: Your public API key
        required: true
        schema:
          type: string
      - name: x-integration-private-key
        in: header
        description: Your private API key
        required: true
        schema:
          type: string
      - name: x-clinic-id
        in: header
        description: The clinic uuid identifier
        required: true
        schema:
          type: string
      responses:
        '200':
          description: A paged collection of messages matching the supplied filter.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RESTCollectionModelBase_OpenApiMessageController.Message'
            text/json:
              schema:
                $ref: '#/components/schemas/RESTCollectionModelBase_OpenApiMessageController.Message'
            application/hal+json:
              schema:
                $ref: '#/components/schemas/RESTCollectionModelBase_OpenApiMessageController.Message'
        '401':
          description: 'Authorization failed. One of: Missing X-Integration-Public-Key header, Missing X-Integration-Private-Key header, Missing X-Clinic-Id header, Incorrect API keys provided, or Integration not enabled for the provided clinic.'
        '429':
          description: Request rate limit exceeded. Please wait before making further requests. Returned once the integration passes its configured hourly or per-minute request allowance.
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OpenApiMessageController.MessageFilterModel'
          text/json:
            schema:
              $ref: '#/components/schemas/OpenApiMessageController.MessageFilterModel'
          application/hal+json:
            schema:
              $ref: '#/components/schemas/OpenApiMessageController.MessageFilterModel'
        description: The model.
        required: true
  /pav2/open-api-messages/write:
    post:
      tags:
      - Message
      summary: Inserts a new {OpenApiMessageController.Message} resource.
      description: 'Example Request

        {

        "clientPhoneNumber": "1234567890",

        "clinicPhoneNumber": "0987654321",

        "content": "Your prescription is ready for pickup.",

        "fromCountry": "USA",

        "isClientMessage": true,

        "numMedia": "0",

        "userId": "f1234567-abcd-4321-89ef-b3c200f01111"

        }


        Example Response

        {

        "embed": null,

        "item": [

        {

        "content": "Your prescription is ready for pickup.",

        "conversation": null,

        "conversationId": "aabbccdd-1234-5678-9101-b3c200f03333",

        "isClientMessage": true,

        "isRead": false,

        "messageStatus": null,

        "messageStatusId": null,

        "orderNum": 0,

        "sendingScheduledFor": "2025-06-27T12:00:00.000Z",

        "sentByUserFormatted": "Reception Bot",

        "sentByUserId": "f1234567-abcd-4321-89ef-b3c200f01111",

        "dateCreated": "2025-06-27T11:55:00.000Z",

        "dateUpdated": "2025-06-27T11:55:00.000Z",

        "id": "99887766-5544-3322-1100-b3c200f04444",

        "links": [null]

        }

        ],

        "links": [],

        "page": 1,

        "recordsPerPage": 10,

        "searchQuery": null,

        "sort": null,

        "totalRecords": 1

        }'
      operationId: OpenApiMessagePost
      parameters:
      - name: x-integration-public-key
        in: header
        description: Your public API key
        required: true
        schema:
          type: string
      - name: x-integration-private-key
        in: header
        description: Your private API key
        required: true
        schema:
          type: string
      - name: x-clinic-id
        in: header
        description: The clinic uuid identifier
        required: true
        schema:
          type: string
      responses:
        '201':
          description: The created message.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RESTCollectionModelBase_OpenApiMessageController.Message'
            text/json:
              schema:
                $ref: '#/components/schemas/RESTCollectionModelBase_OpenApiMessageController.Message'
            application/hal+json:
              schema:
                $ref: '#/components/schemas/RESTCollectionModelBase_OpenApiMessageController.Message'
        '401':
          description: 'Authorization failed. One of: Missing X-Integration-Public-Key header, Missing X-Integration-Private-Key header, Missing X-Clinic-Id header, Incorrect API keys provided, or Integration not enabled for the provided clinic.'
        '429':
          description: Request rate limit exceeded. Please wait before making further requests. Returned once the integration passes its configured hourly or per-minute request allowance.
        '400':
          description: '"The request is invalid." with one modelState entry per missing or blank field:

            The ClientPhoneNumber field is required.

            The ClinicPhoneNumber field is required.

            The Content field is required.

            The FromCountry field is required.

            The NumMedia field is required.

            "The request is invalid." without modelState:

            The request is invalid. - messaging is not shared and clinicPhoneNumber is not the messaging number of the clinic in X-Clinic-Id. When messaging is shared, clinicPhoneNumber is not checked.

            The request is invalid. - the country for the supplied clientPhoneNumber could not be resolved, either from fromCountry or from the number''s international dialling prefix.

            No envelope - the body is the message itself, as a JSON string:

            MESSAGING.CONVERSATION.SMS_PHONE_NUMBER_INVALID - Message not sent: This number can''t receive text messages. Reached only when the message triggers an automatic appointment-confirmation reply and the client phone number cannot receive SMS.

            MESSAGING.CONVERSATION.ERROR_MISSING_BILLING_CLINIC - Message failed to send. SMS Billing clinic not set. Same appointment-confirmation reply path, only when the group shares messaging, has no SMS billing clinic configured, has automatic SMS block purchase enabled, and the reply would leave the group''s SMS allocation at or below its threshold.

            MESSAGING.FIND.CLINIC_SMS_MISSING - The conversation doesn''t exist. Same appointment-confirmation reply path, when the clinic belongs to a demo group: demo groups never send SMS, so the automatic reply cannot be sent.'
        '409':
          description: '"Resource already exists." with errorCode 23505. The body does not say which cause applied.

            Reached only when the message triggers an automatic appointment-confirmation reply that cannot be sent, because either:

            the client has unsubscribed from SMS, or

            the number passed phone validation, but the SMS provider rejected the reply as not deliverable by text message.'
        '500':
          description: '"Unhandled error occurred, please contact support team." Returned when the message triggers an automatic appointment-confirmation reply.

            Despite the error, the message and the reply are saved and the reply SMS is queued for sending, so retrying sends the reply again.'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OpenApiMessageController.MessageWriteModel'
          text/json:
            schema:
              $ref: '#/components/schemas/OpenApiMessageController.MessageWriteModel'
          application/hal+json:
            schema:
              $ref: '#/components/schemas/OpenApiMessageController.MessageWriteModel'
        description: The model.
        required: true
components:
  schemas:
    OpenApiMessageController.ConversationAssignedToUser:
      description: Conversation Assigned To User REST model.
      type: object
      properties:
        userId:
          description: Unique identifier representing the related User entity.
          type: string
        dateCreated:
          format: date-time
          type: string
        dateUpdated:
          format: date-time
          type: string
        id:
          type: string
    OpenApiMessageController.Message:
      description: Message REST model.
      type: object
      properties:
        content:
          description: Free-text field indicating Content of message.
          type: string
        conversation:
          $ref: '#/components/schemas/OpenApiMessageController.Conversation'
          description: Object representing the related Conversation entity.
        conversationId:
          description: Unique identifier representing the related Conversation entity.
          type: string
        isClientMessage:
          description: Flag indicating whether the client sent or received this message
          type: boolean
        isRead:
          description: Flag indicating whether this message has been read.
          type: boolean
        messageStatus:
          $ref: '#/components/schemas/OpenApiMessageController.MessageStatus'
          description: Object representing the related Message status entity.
        messageStatusId:
          description: Unique identifier representing the Message status entity.
          type: string
        orderNum:
          format: int32
          description: Global order number of message.
          type: integer
        sendingScheduledFor:
          format: date-time
          description: Time when the message Sending is scheduled for
          type: string
          readOnly: true
        sentByUserFormatted:
          description: Full name of the user who sent the message, including the prefix and suffix.
          type: string
        sentByUserId:
          description: Unique identifier representing the user who sent the message.
          type: string
        dateCreated:
          format: date-time
          type: string
        dateUpdated:
          format: date-time
          type: string
        id:
          type: string
    RESTCollectionModelBase_OpenApiMessageController.Message:
      type: object
      properties:
        embed:
          type: string
        item:
          type: array
          items:
            $ref: '#/components/schemas/OpenApiMessageController.Message'
        page:
          format: int32
          type: integer
        recordsPerPage:
          format: int32
          type: integer
        searchQuery:
          type: string
        sort:
          type: string
        totalRecords:
          format: int32
          type: integer
    OpenApiMessageController.MessageFilterModel:
      description: Message Filter REST model
      type: object
      properties:
        assignedUserIds:
          description: Filters by the assigned user ids.
          type: string
        clinicIds:
          description: Comma-separated list of Clinic identifiers. Defaults to null. The filter is applicable only if the group to which the clinic belongs shares messaging. If this filter is provided, response data will be overridden with clinic messaging data.
          type: string
        conversationIds:
          description: Filters by the conversation ids.
          type: string
        isConversationDeleted:
          description: Filters by whether the message's conversation has been deleted. Deleting a conversation does not flag its messages, so pass false here, not only isDeleted, to leave out messages of deleted conversations.
          type: boolean
        isDeleted:
          description: Flag indicating whether the message has been deleted.
          type: boolean
        messageStatusIds:
          description: Filters by the message status ids.
          type: string
        searchQuery:
          description: Filters by message content.
          type: string
        dateCreatedFrom:
          format: date-time
          description: 'Sets the start of the date range filter on the entity creation date. Must not be later than DateCreatedTo, or

            the request returns 400. Defaults to null.'
          type: string
        dateCreatedTo:
          format: date-time
          description: The end of the date range filter on the entity creation date. Defaults to null.
          type: string
        dateUpdatedFrom:
          format: date-time
          description: 'The start of the date range filter on the entity last update date. Must not be later than DateUpdatedTo, or the

            request returns 400. Defaults to null.'
          type: string
        dateUpdatedTo:
          format: date-time
          description: The end of the date range filter on the entity last update date. Defaults to null.
          type: string
        embed:
          description: Comma-separated list of embedded properties to fetch. Nested fetches can be specified using dot notation (e.g., "client.clientPhones"). Defaults to null.
          type: string
        excludeIds:
          description: Comma-separated list of IDs representing entities that you wish to exclude from your search. Defaults to null.
          type: string
        ids:
          description: Comma-separated list of IDs representing entities that you wish to include in your search. Defaults to null.
          type: string
        page:
          format: int32
          description: The page number. Defaults to 1.
          type: integer
        rpp:
          format: int32
          description: The number of items to return per page. The max is 1000. Defaults to 10.
          type: integer
        sort:
          description: Which field to sort by. Needs to be in "field|order" format, where order is either "asc" or "desc". The default sort field depends on the endpoint, typically "id|asc"
          type: string
    OpenApiMessageController.MessageWriteModel:
      description: Message Write REST model
      required:
      - clientPhoneNumber
      - clinicPhoneNumber
      - content
      - fromCountry
      - numMedia
      type: object
      properties:
        clientPhoneNumber:
          description: Value representing Client's phone number (e.g. "1213213123").
          type: string
        clinicPhoneNumber:
          description: Value representing Clinic's phone number (e.g. "1234567891").
          type: string
        content:
          description: Free-text field indicating Content of message.
          type: string
        fromCountry:
          description: Value representing the Country where sender of the message comes from.
          type: string
        isClientMessage:
          description: Value indicating whether the client sent or received this message
          type: boolean
        numMedia:
          description: The number of media files in message.
          type: string
        userId:
          description: Unique identifier of the related user entity. Represents the clinic users who sent message.
          type: string
    OpenApiMessageController.Conversation:
      description: Conversation REST model.
      type: object
      properties:
        clientId:
          description: Unique identifier representing the related Client entity.
          type: string
        conversationAssignedToUsers:
          description: List of objects representing the Conversation assigned to users.
          type: array
          items:
            $ref: '#/components/schemas/OpenApiMessageController.ConversationAssignedToUser'
        conversationStatusId:
          description: Unique identifier representing the related Conversation status entity.
          type: string
        isDeleted:
          description: Flag indicating whether this Conversation has been deleted. Deleting a conversation does not flag its messages as deleted.
          type: boolean
        isReminder:
          description: Flag indicating whether this Conversation is sent from reminder. It is set automatically by the clinic.
          type: boolean
        dateCreated:
          format: date-time
          type: string
        dateUpdated:
          format: date-time
          type: string
        id:
          type: string
    OpenApiMessageController.MessageStatus:
      description: MessageStatus REST model.
      type: object
      properties:
        abrv:
          description: Short unique identifier for the lookup.
          type: string
        description:
          description: The description of the lookup entry.
          type: string
        name:
          description: The name of the lookup entry.
          type: string
        dateCreated:
          format: date-time
          type: string
        dateUpdated:
          format: date-time
          type: string
        id:
          type: string