I am trying to create a custom webhook trigger. My POST and DEL requests work in Postman and Test in the custom connector. In fact, I am copying and pasting my working sample URLs directly from Postman.
Yet on updating the connector with 'Update connector', the webhook is not created (should be the latest id). No error is shown when updating the connector.
The help text states the Location header and DEL Action are required, so I confirmed the create webhook response includes the Location header which is in format:
http://na.myconnectwise.net/v2020_3/apis/3.0/system/callbacks/{id}
I then created the DEL Action (which again works in Postman and Test) that has exact same URL and format as the Location header. This did not help.
The Swagger Editor does have error "Structural error at paths./system/callbacks/.post.responses should define at least one response" line 493 but the help text explicitly states "You do NOT need to define the response of the request that creates and registers the webhook" (I have already imported my sample response for the webhook trigger which I know is separate from the create webhook response).
Swagger:
swagger: '2.0'
info: {title: Default title, description: '', version: '1.0'}
host: na.myconnectwise.net
basePath: /v2020_3/apis/3.0/
schemes: [https]
consumes: []
produces: []
paths:
/v4_6_development/apis/3.0/service/tickets: {}
/v4_6_release/apis/3.0/service/tickets: {}
/v4_6_release/apis/3.0/system/callbacks:
x-ms-notification-content:
description: New Time Entry
schema:
type: object
properties:
FromUrl: {type: string, description: FromUrl}
CompanyId: {type: string, description: CompanyId}
MemberId: {type: string, description: request.MemberId, title: request.MemberId}
Action: {type: string, description: Action}
Type: {type: string, description: request.Type, title: request.Type}
ID: {type: integer, format: int32, description: request.ID, title: request.ID}
Entity:
type: object
properties:
id: {type: integer, format: int32, description: timeEntry.id, title: timeEntry.id}
company:
type: object
properties:
id: {type: integer, format: int32, description: company.id, title: company.id}
identifier: {type: string, description: company.identifier, title: company.identifier}
name: {type: string, description: company.name, title: company.name}
_info:
type: object
properties:
company_href: {type: string, description: company_href}
mobileGuid: {type: string, description: mobileGuid}
description: _info
description: company
chargeToId: {type: integer, format: int32, description: chargeToId}
chargeToType: {type: string, description: chargeToType}
member:
type: object
properties:
id: {type: integer, format: int32, description: member.id, title: member.id}
identifier: {type: string, description: member.identifier, title: member.identifier}
name: {type: string, description: member.name, title: member.name}
_info:
type: object
properties:
member_href: {type: string, description: member_href}
image_href: {type: string, description: image_href}
description: _info
description: member
locationId: {type: integer, format: int32, description: locationId}
businessUnitId: {type: integer, format: int32, description: businessUnitId}
workType:
type: object
properties:
id: {type: integer, format: int32, description: workType.id, title: workType.id}
name: {type: string, description: workType.name, title: workType.name}
_info:
type: object
properties:
workType_href: {type: string, description: workType_href}
description: _info
description: workType
workRole:
type: object
properties:
id: {type: integer, format: int32, description: workRole.id, title: workRole.id}
name: {type: string, description: workRole.name, title: workRole.name}
_info:
type: object
properties:
workRole_href: {type: string, description: workRole_href}
description: _info
description: workRole
timeStart: {type: string, description: timeStart}
timeEnd: {type: string, description: timeEnd}
hoursDeduct: {type: integer, format: int32, description: hoursDeduct}
actualHours: {type: integer, format: int32, description: actualHours}
billableOption: {type: string, description: billableOption}
notes: {type: string, description: notes}
addToDetailDescriptionFlag: {type: boolean, description: addToDetailDescriptionFlag}
addToInternalAnalysisFlag: {type: boolean, description: addToInternalAnalysisFlag}
addToResolutionFlag: {type: boolean, description: addToResolutionFlag}
emailResourceFlag: {type: boolean, description: emailResourceFlag}
emailContactFlag: {type: boolean, description: emailContactFlag}
emailCcFlag: {type: boolean, description: emailCcFlag}
emailCc: {type: string, description: emailCc}
hoursBilled: {type: integer, format: int32, description: hoursBilled}
enteredBy: {type: string, description: enteredBy}
dateEntered: {type: string, description: dateEntered}
mobileGuid: {type: string, description: mobileGuid}
hourlyRate: {type: integer, format: int32, description: hourlyRate}
agreementHours: {type: integer, format: int32, description: agreementHours}
agreementAmount: {type: integer, format: int32, description: agreementAmount}
timeSheet:
type: object
properties:
id: {type: integer, format: int32, description: timeSheet.id, title: timeSheet.id}
name: {type: string, description: timeSheet.name, title: timeSheet.name}
_info:
type: object
properties:
timeSheet_href: {type: string, description: timeSheet_href}
description: _info
description: timeSheet
status: {type: string, description: status}
ticket:
type: object
properties:
id: {type: integer, format: int32, description: ticket.id, title: ticket.id}
summary: {type: string, description: ticket.summary, title: ticket.summary}
_info:
type: object
properties:
ticket_href: {type: string, description: ticket_href}
billingMethod: {type: string, description: billingMethod}
description: _info
description: ticket
_info:
type: object
properties:
lastUpdated: {type: string, description: lastUpdated}
updatedBy: {type: string, description: updatedBy}
chargeToMobileGuid: {type: string, description: chargeToMobileGuid}
description: _info
description: Entity
Metadata:
type: object
properties:
key_url: {type: string, description: key_url}
description: Metadata
CallbackObjectRecId: {type: integer, format: int32, description: CallbackObjectRecId}
/v4_6_release/apis/3.0/project/projects: {}
/v4_6_release/apis/3.0/procurement/products: {}
/v4_6_release/apis/3.0/procurement/catalog: {}
/v4_6_release/apis/3.0/system/callbacks/: {}
/v2020_3/apis/3.0/system/callbacks/:
x-ms-notification-content:
description: New Time Entry
schema:
type: object
properties:
FromUrl: {type: string, description: FromUrl}
CompanyId: {type: string, description: CompanyId}
MemberId: {type: string, description: request.MemberId, title: request.MemberId}
Action: {type: string, description: Action}
Type: {type: string, description: request.Type, title: request.Type}
ID: {type: integer, format: int32, description: request.ID, title: request.ID}
Entity:
type: object
properties:
id: {type: integer, format: int32, description: timeEntry.id, title: timeEntry.id}
company:
type: object
properties:
id: {type: integer, format: int32, description: company.id, title: company.id}
identifier: {type: string, description: company.identifier, title: company.identifier}
name: {type: string, description: company.name, title: company.name}
_info:
type: object
properties:
company_href: {type: string, description: company_href}
mobileGuid: {type: string, description: mobileGuid}
description: _info
description: company
chargeToId: {type: integer, format: int32, description: chargeToId}
chargeToType: {type: string, description: chargeToType}
member:
type: object
properties:
id: {type: integer, format: int32, description: member.id, title: member.id}
identifier: {type: string, description: member.identifier, title: member.identifier}
name: {type: string, description: member.name, title: member.name}
_info:
type: object
properties:
member_href: {type: string, description: member_href}
image_href: {type: string, description: image_href}
description: _info
description: member
locationId: {type: integer, format: int32, description: locationId}
businessUnitId: {type: integer, format: int32, description: businessUnitId}
workType:
type: object
properties:
id: {type: integer, format: int32, description: workType.id, title: workType.id}
name: {type: string, description: workType.name, title: workType.name}
_info:
type: object
properties:
workType_href: {type: string, description: workType_href}
description: _info
description: workType
workRole:
type: object
properties:
id: {type: integer, format: int32, description: workRole.id, title: workRole.id}
name: {type: string, description: workRole.name, title: workRole.name}
_info:
type: object
properties:
workRole_href: {type: string, description: workRole_href}
description: _info
description: workRole
timeStart: {type: string, description: timeStart}
timeEnd: {type: string, description: timeEnd}
hoursDeduct: {type: integer, format: int32, description: hoursDeduct}
actualHours: {type: integer, format: int32, description: actualHours}
billableOption: {type: string, description: billableOption}
notes: {type: string, description: notes}
addToDetailDescriptionFlag: {type: boolean, description: addToDetailDescriptionFlag}
addToInternalAnalysisFlag: {type: boolean, description: addToInternalAnalysisFlag}
addToResolutionFlag: {type: boolean, description: addToResolutionFlag}
emailResourceFlag: {type: boolean, description: emailResourceFlag}
emailContactFlag: {type: boolean, description: emailContactFlag}
emailCcFlag: {type: boolean, description: emailCcFlag}
emailCc: {type: string, description: emailCc}
hoursBilled: {type: integer, format: int32, description: hoursBilled}
enteredBy: {type: string, description: enteredBy}
dateEntered: {type: string, description: dateEntered}
mobileGuid: {type: string, description: mobileGuid}
hourlyRate: {type: integer, format: int32, description: hourlyRate}
agreementHours: {type: integer, format: int32, description: agreementHours}
agreementAmount: {type: integer, format: int32, description: agreementAmount}
timeSheet:
type: object
properties:
id: {type: integer, format: int32, description: timeSheet.id, title: timeSheet.id}
name: {type: string, description: timeSheet.name, title: timeSheet.name}
_info:
type: object
properties:
timeSheet_href: {type: string, description: timeSheet_href}
description: _info
description: timeSheet
status: {type: string, description: status}
ticket:
type: object
properties:
id: {type: integer, format: int32, description: ticket.id, title: ticket.id}
summary: {type: string, description: ticket.summary, title: ticket.summary}
_info:
type: object
properties:
ticket_href: {type: string, description: ticket_href}
billingMethod: {type: string, description: billingMethod}
description: _info
description: ticket
_info:
type: object
properties:
lastUpdated: {type: string, description: lastUpdated}
updatedBy: {type: string, description: updatedBy}
chargeToMobileGuid: {type: string, description: chargeToMobileGuid}
description: _info
description: Entity
Metadata:
type: object
properties:
key_url: {type: string, description: key_url}
description: Metadata
CallbackObjectRecId: {type: integer, format: int32, description: CallbackObjectRecId}
/service/tickets:
get:
responses:
default:
description: default
schema:
type: array
items:
type: object
properties:
id: {type: integer, format: int32, description: id}
summary: {type: string, description: summary}
board:
type: object
properties:
name: {type: string, description: name}
description: board
status:
type: object
properties:
name: {type: string, description: name}
description: status
company:
type: object
properties:
name: {type: string, description: name}
description: company
resources: {type: string, description: resources}
_info:
type: object
properties:
dateEntered: {type: string, description: dateEntered}
description: _info
summary: Get Service Tickets
operationId: Get_Service_Tickets
parameters:
- {name: conditions, in: query, required: false, type: string}
- {name: pageSize, in: query, required: false, type: integer}
- {name: fields, in: query, required: false, type: string}
- {name: orderBy, in: query, required: false, type: string}
- {name: clientID, in: header, required: true, type: string, default: REDACTED,
x-ms-visibility: internal}
- {name: Content-Type, in: header, required: true, type: string, default: application/json;
charset=utf-8, x-ms-visibility: internal}
description: Get Service Tickets
/project/projects:
get:
responses:
default:
description: default
schema: {}
summary: Get Project List
description: Retrieves project number, project name, start date and company.
operationId: Get_Project_list
parameters:
- {name: conditions, in: query, required: true, type: string, default: status/name
!= 'Closed-Ready to Bill' AND department/identifier = 'IT Services'}
- {name: fields, in: query, required: true, type: string, default: 'id,actualStart,company/name,name'}
- {name: pageSize, in: query, required: false, type: string}
- {name: orderBy, in: query, required: false, type: string}
- {name: clientID, in: header, required: true, type: string, default: REDACTED,
x-ms-visibility: internal}
- {name: Content-Type, in: header, required: true, type: string, default: application/json;
charset=utf-8, x-ms-visibility: internal}
/procurement/catalog:
get:
responses:
default:
description: default
schema: {}
summary: Get Products from Catalog
operationId: Get_Products
description: Get Products from Catalog
parameters:
- {name: conditions, in: query, required: false, type: string, description: 'example:
identifier = "Replibit Cloud backup License" AND description CONTAINS "Data"'}
- {name: fields, in: query, required: false, type: string, default: 'id,identifier,description,cost,price',
description: Fields to return. Leave default if unsure.}
- {name: pageSize, in: query, required: false, type: integer, default: 1, description: Number
of results to return.}
- {name: orderBy, in: query, required: false, type: string, description: 'example:
_info/lastUpdated DESC'}
- {name: clientID, in: header, required: true, type: string, default: REDACTED,
x-ms-visibility: internal}
- {name: Content-Type, in: header, required: true, type: string, default: application/json;
charset=utf-8, x-ms-visibility: internal}
/system/callbacks/{id}:
delete:
responses:
default:
description: default
schema: {}
summary: DELETE New_Time_Entry Webhook
operationId: DELETE_New_Time_Entry_Webhook
parameters:
- {name: id, in: path, required: true, type: string}
- {name: clientID, in: header, required: true, type: string, default: REDACTED,
x-ms-visibility: internal}
- {name: Content-Type, in: header, required: true, type: string, default: application/json;
charset=utf-8, x-ms-visibility: internal}
/system/callbacks/:
x-ms-notification-content:
description: New Time Entry
schema:
type: object
properties:
FromUrl: {type: string, description: FromUrl}
CompanyId: {type: string, description: CompanyId}
MemberId: {type: string, description: request.MemberId, title: request.MemberId}
Action: {type: string, description: Action}
Type: {type: string, description: request.Type, title: request.Type}
ID: {type: integer, format: int32, description: request.ID, title: request.ID}
Entity:
type: object
properties:
id: {type: integer, format: int32, description: timeEntry.id, title: timeEntry.id}
company:
type: object
properties:
id: {type: integer, format: int32, description: company.id, title: company.id}
identifier: {type: string, description: company.identifier, title: company.identifier}
name: {type: string, description: company.name, title: company.name}
_info:
type: object
properties:
company_href: {type: string, description: company_href}
mobileGuid: {type: string, description: mobileGuid}
description: _info
description: company
chargeToId: {type: integer, format: int32, description: chargeToId}
chargeToType: {type: string, description: chargeToType}
member:
type: object
properties:
id: {type: integer, format: int32, description: member.id, title: member.id}
identifier: {type: string, description: member.identifier, title: member.identifier}
name: {type: string, description: member.name, title: member.name}
_info:
type: object
properties:
member_href: {type: string, description: member_href}
image_href: {type: string, description: image_href}
description: _info
description: member
locationId: {type: integer, format: int32, description: locationId}
businessUnitId: {type: integer, format: int32, description: businessUnitId}
workType:
type: object
properties:
id: {type: integer, format: int32, description: workType.id, title: workType.id}
name: {type: string, description: workType.name, title: workType.name}
_info:
type: object
properties:
workType_href: {type: string, description: workType_href}
description: _info
description: workType
workRole:
type: object
properties:
id: {type: integer, format: int32, description: workRole.id, title: workRole.id}
name: {type: string, description: workRole.name, title: workRole.name}
_info:
type: object
properties:
workRole_href: {type: string, description: workRole_href}
description: _info
description: workRole
timeStart: {type: string, description: timeStart}
timeEnd: {type: string, description: timeEnd}
hoursDeduct: {type: integer, format: int32, description: hoursDeduct}
actualHours: {type: integer, format: int32, description: actualHours}
billableOption: {type: string, description: billableOption}
notes: {type: string, description: notes}
addToDetailDescriptionFlag: {type: boolean, description: addToDetailDescriptionFlag}
addToInternalAnalysisFlag: {type: boolean, description: addToInternalAnalysisFlag}
addToResolutionFlag: {type: boolean, description: addToResolutionFlag}
emailResourceFlag: {type: boolean, description: emailResourceFlag}
emailContactFlag: {type: boolean, description: emailContactFlag}
emailCcFlag: {type: boolean, description: emailCcFlag}
emailCc: {type: string, description: emailCc}
hoursBilled: {type: integer, format: int32, description: hoursBilled}
enteredBy: {type: string, description: enteredBy}
dateEntered: {type: string, description: dateEntered}
mobileGuid: {type: string, description: mobileGuid}
hourlyRate: {type: integer, format: int32, description: hourlyRate}
agreementHours: {type: integer, format: int32, description: agreementHours}
agreementAmount: {type: integer, format: int32, description: agreementAmount}
timeSheet:
type: object
properties:
id: {type: integer, format: int32, description: timeSheet.id, title: timeSheet.id}
name: {type: string, description: timeSheet.name, title: timeSheet.name}
_info:
type: object
properties:
timeSheet_href: {type: string, description: timeSheet_href}
description: _info
description: timeSheet
status: {type: string, description: status}
ticket:
type: object
properties:
id: {type: integer, format: int32, description: ticket.id, title: ticket.id}
summary: {type: string, description: ticket.summary, title: ticket.summary}
_info:
type: object
properties:
ticket_href: {type: string, description: ticket_href}
billingMethod: {type: string, description: billingMethod}
description: _info
description: ticket
_info:
type: object
properties:
lastUpdated: {type: string, description: lastUpdated}
updatedBy: {type: string, description: updatedBy}
chargeToMobileGuid: {type: string, description: chargeToMobileGuid}
description: _info
description: Entity
Metadata:
type: object
properties:
key_url: {type: string, description: key_url}
description: Metadata
CallbackObjectRecId: {type: integer, format: int32, description: CallbackObjectRecId}
post:
responses: {}
summary: New Time Entry
operationId: New_Time_Entry
x-ms-trigger: single
parameters:
- {name: clientID, in: header, required: true, type: string, default: REDACTED,
x-ms-visibility: internal}
- {name: Content-Type, in: header, required: true, type: string, default: application/json;
charset=utf-8, x-ms-visibility: internal}
- name: body
in: body
required: false
schema:
type: object
properties:
url: {type: string, description: url, x-ms-visibility: internal, title: '',
x-ms-notification-url: true}
objectId: {type: integer, format: int32, description: objectId, title: '',
default: 1, x-ms-visibility: internal}
type: {type: string, description: type, title: '', default: time, x-ms-visibility: internal}
level: {type: string, description: level, title: '', default: owner, x-ms-visibility: internal}
required: [level, objectId, type, url]
description: Do something when new time entry is created
x-ms-visibility: important
definitions: {}
parameters: {}
responses: {}
securityDefinitions:
basic_auth: {type: basic}
security:
- basic_auth: []
tags: []
Anyone able to help?