PSA abstraction layer with provider pattern, ConnectWise integration (connection management, ticket linking, note posting, status updates, member mapping), Integrations page UI, Fernet credential encryption, in-memory TTL cache, 6 DB migrations, ConnectWise API reference docs.
231 lines
14 KiB
Markdown
231 lines
14 KiB
Markdown
1. Last updated
|
||
|
||
Feb 4, 2026
|
||
|
||
2. [Save as PDF](https://developer.connectwise.com/@api/deki/pages/859/pdf/PSA%2bCallbacks.pdf "Export page as a PDF")
|
||
|
||
ConnectWise PSA callbacks are payloads of information that are similar to webhooks. When a record is saved within PSA, a summarized payload is sent to a specified location.
|
||
|
||
### Levels and Types
|
||
|
||
The REST APIs allow a more granular approach to callbacks. Levels and types open the ability to report on specific boards or tickets without getting unnecessary results.
|
||
|
||
|**Type**|**Level**|**Description**|
|
||
|---|---|---|
|
||
|Activities \-|
|
||
|Activity|Owner|When set to owner, all ConnectWise PSA activities are returned.|
|
||
|Activity|Status|Receive callbacks for activities in the specified status.|
|
||
|Activity|Type|Receive callbacks for activities in the specified type.|
|
||
|Activity|Company|Receive callbacks for activities under a specific company.|
|
||
|Activity|Activity|Receive callbacks for specific activity.|
|
||
|Agreements \-|
|
||
|Agreement|Owner|When set to owner, all ConnectWise PSA agreements are returned.|
|
||
|Agreement|Type|Receive callbacks for agreements in the specified type.|
|
||
|Agreement|Company|Receive callbacks for agreements under a specific company.|
|
||
|Agreement|Agreement|Recieve callbacks for specific agreement.|
|
||
|Companies \-|
|
||
|Company|Owner|When set to owner, all ConnectWise PSA companies are returned.|
|
||
|Company|Status|Receive callbacks for companies in the specified status.|
|
||
|Company|Type|Receive callbacks for companies in the specified type.|
|
||
|Company|Territory|Receive callbacks for companies in the specified territory.|
|
||
|Company|Company|Receive callbacks for specific company regardless of territory.|
|
||
|Company|IntegratorTag|Tag companies to only get updates for that company with one callback record|
|
||
|Contacts \-|
|
||
|Contact|Owner|When set to owner, all ConnectWise PSA contacts are returned.|
|
||
|Contact|Type|Receive callbacks for contacts in the specified type.|
|
||
|Contact|Territory|Receive callbacks for contacts in the specified territory.|
|
||
|Contact|Company|Receive callbacks for contacts under a specific company.|
|
||
|Contact|Contact|Receive callbacks for specific contact.|
|
||
|Configurations \-|
|
||
|Configuration|Owner|When set to owner, all ConnectWise PSA configurations are returned.|
|
||
|Configuration|Type|Receive callbacks for configurations in the specified type.|
|
||
|Configuration|Status|Receive callbacks for contacts in the specified status.|
|
||
|Configuration|Configuration|Receive callbacks for a specific configuration.|
|
||
|Invoice \-|
|
||
|Invoice|Owner|When set to owner, all ConnectWise PSA invoices are returned.|
|
||
|Invoice|Status|Receive callbacks for invoices in the specified status.|
|
||
|Invoice|Company|Receive callbacks for invoices under a specific company.|
|
||
|Invoice|Invoice|Receive callbacks for specific invoice.|
|
||
|Expense \-|
|
||
|Expense|Owner|When set to owner, all ConnectWise PSA expenses are returned.|
|
||
|Expense|ChargeToType|Receive callbacks for expenses under the specified ChargeToType.|
|
||
|Expense|Type|Receive callbacks for expenses under the specified Type.|
|
||
|Expense|Class|Receive callbacks for expenses under the specified Class.|
|
||
|Expense|Company|Receive callbacks for expenses under the specified Company.|
|
||
|Expense|Expense|Receive calbacks for specific expense.|
|
||
|Member \-|
|
||
|Member|Owner|When set to owner, changes to all ConnectWise PSA member records are returned.|
|
||
|Member|Location|Receive callbacks for member records associated with the specified Location.|
|
||
|Member|SecurityRole|Receive callbacks for member records associated with the specified Security Role.|
|
||
|Member|Member|Receive callbacks for changes made to a specified member record.|
|
||
|Opportunities \-|
|
||
|Opportunity|Owner|When set to owner, all ConnectWise PSA opportunities are returned.|
|
||
|Opportunity|StatusId|Receive callbacks for opportunities in the specified status.|
|
||
|Opportunity|Company|Receive callbacks for opportunities under a specific company.|
|
||
|Opportunity|Opportunity|Receive callbacks for specific opportunity.|
|
||
|Product Catalog \-|
|
||
|ProductCatalog|Owner|When set to owner, all ConnectWise PSA product catalog items are returned.|
|
||
|Projects \-|
|
||
|Project|Owner|When set to owner, all ConnectWise PSA projects are returned.|
|
||
|Project|Status|Receive callbacks for projects in the specified status.|
|
||
|Project|Board|Receive callbacks for projects on the specified board.|
|
||
|Project|Project|Receive callbacks for specific project.|
|
||
|Purchase Orders \-|
|
||
|PurchaseOrder|Owner|When set to owner, all ConnectWise PSA purchase orders are returned.|
|
||
|PurchaseOrder|Status|Receive callbacks for purchase orders in the specified status.|
|
||
|PurchaseOrder|Vendor|Receive callbacks for purchase orders under the specified Vendor.|
|
||
|PurchaseOrder|Company|Receive callbacks for purchase orders under a specific company.|
|
||
|PurchaseOrder|PurchaseOrder|Receive callbacks for specific purchase orders.|
|
||
|Schedule Entries \-|
|
||
|Schedule|Owner|When set to owner, all ConnectWise PSA schedule entries are returned.|
|
||
|Schedule|Status|Receive callbacks for schedule entries under a specific status.|
|
||
|Schedule|Type|Receive callbacks for schedule entries under a specific type.|
|
||
|Schedule|Location|Receive callbacks for schedule entries under a specific location.|
|
||
|Schedule|Member|Receive callbacks for schedule entries under a specific member.|
|
||
|Schedule|Schedule|Receive callbacks for specific schedule entries.|
|
||
|Sites \-|
|
||
|Site|Owner|When set to owner, all ConnectWise PSA sites are returned.|
|
||
|Site|Territory|Receive callbacks for sites in specified territory.|
|
||
|Site|Company|Receive callbacks for sites associated with a specific company.|
|
||
|Site|Site|Receive callbacks for specific site.|
|
||
|Tickets \-|
|
||
|Ticket|Owner|When set to owner, all ConnectWise PSA tickets are returned.|
|
||
|Ticket|Board|Receive callbacks for tickets on the specified board.|
|
||
|Ticket|Project|Receive callbacks for tickets attached to a specific project.|
|
||
|Ticket|Phase|Receive callbacks for tickets attached to a specific project phase.|
|
||
|Ticket|Status|Receive callbacks for tickets in the specified status.|
|
||
|Ticket|Ticket|Receive callbacks for specific tickets.|
|
||
|Ticket|IntegratorTag|Tag tickets to only get updates for that ticket with one callback record|
|
||
|Time Entries \-|
|
||
|Time|Owner|When set to owner, all ConnectWise PSA time entries are returned.|
|
||
|Time|Company|Receive callbacks for tickets for the specified company.|
|
||
|Time|Time|Receive callbacks for specific time entries.|
|
||
|
||
### Configuring the Callbacks
|
||
|
||
More information can be found within the REST API documentation [Here](https://developer.connectwise.com/Products/ConnectWise_PSA/REST#/CallbackEntries "https://developer.connectwise.com/Products/Manage/REST#/CallbackEntries") with the endpoint system/callbacks.
|
||
|
||
|**Fields**|**Description**|
|
||
|---|---|
|
||
|Id|The database record id of the callback; is automatically assigned.|
|
||
|Description|This is used to label the callback's usage.|
|
||
|URL|This is the URL PSA will send the POST payload to.
|
||
**Note**: PSA appends the record id, and action is taken, to the specified callback URL.
|
||
For example, a callback on ticket 7601, turns the callback URL into: [https://mycallbacksite.com/e355a80bc2c107e32](https://mycallbacksite.com/e355a80bc2c107e32 "https://mycallbacksite.com/e355a80bc2c107e32")_?7601&action=updated_
|
||
Typically, this is not an issue. However, when it is necessary to add custom parameters to your callback URL, this can cause a problem. For this reason, it is recommended that partners append _&recordId=_ to the end of their callback URL, like: [https://mycallbacksite.com/e355a80bc2c107e32](https://mycallbacksite.com/e355a80bc2c107e32 "https://mycallbacksite.com/e355a80bc2c107e32")**_&recordId=_**. This will ensure that the record id does not interfere with any custom parameters.
|
||
Example:
|
||
Desired callback URL: [https://api.mycallbackendpoint.com?param1=5¶m2=6](https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fapi.mycallbackendpoint.com%2F%3Fparam1%3D5%26param2%3D6&data=05%7C01%7CRBodford%40connectwise.com%7C3deeae87cf1245c0a98008db0301ab7e%7Cf2ddb62f83354cc99886175b834e4bf3%7C0%7C0%7C638107077950837811%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=6dopNZzGSRoM5HMUn%2BzhlV0UV3DeZizIxiwMajv5eXE%3D&reserved=0 "Original URL: https://api.mycallbackendpoint.com/?param1=5¶m2=6. Click or tap if you trust this link.")
|
||
Currently, a callback on ticket number 2475 turns the callback URL into:
|
||
[https://api.mycallbackendpoint.com?param1=5¶m2=62475&action=updated](https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fapi.mycallbackendpoint.com%2F%3Fparam1%3D5%26param2%3D62475%26action%3Dupdated&data=05%7C01%7CRBodford%40connectwise.com%7C3deeae87cf1245c0a98008db0301ab7e%7Cf2ddb62f83354cc99886175b834e4bf3%7C0%7C0%7C638107077950837811%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=2BxWDta4VObPj81GAHDOWTxyrtYmj3AxTo8MYp3mxv4%3D&reserved=0 "Original URL: https://api.mycallbackendpoint.com/?param1=5¶m2=62475&action=updated. Click or tap if you trust this link.")
|
||
Notice the value of param2 is now changed from 6 to 62475 because the ticket number was appended.
|
||
This results in the following URL:
|
||
[https://api.mycallbackendpoint.com?param1=5¶m2=6&recordId=2475&action=updated](https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fapi.mycallbackendpoint.com%2F%3Fparam1%3D5%26param2%3D6%26recordId%3D2475%26action%3Dupdated&data=05%7C01%7CRBodford%40connectwise.com%7C3deeae87cf1245c0a98008db0301ab7e%7Cf2ddb62f83354cc99886175b834e4bf3%7C0%7C0%7C638107077950994009%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=GwH9Y77%2Be5wgOxXwy%2FD1HXx4XRII%2FgE8eFCu7pyLafw%3D&reserved=0 "Original URL: https://api.mycallbackendpoint.com/?param1=5¶m2=6&recordId=2475&action=updated. Click or tap if you trust this link.")|
|
||
|ObjectId|The ObjectId should be the Id of whatever record you are subscribing to. This should be set to 1 when using a level of Owner.|
|
||
|Type|This is the specific type of record such as Company, Ticket, Contact, etc... See the associated table for all values.|
|
||
|Level|The level is used to determine how granular the callback subscription will be. See the associated table for all values.|
|
||
|MemberId|This is a read-only value that shows who initially created the Callback.|
|
||
|InactiveFlag|Used to determine if the callback is active and sending requests.|
|
||
|\_Info|This section has additional metadata about the record and is included on all API requests as read-only data.|
|
||
|
||
|`01`|`POST /v4_6_release/apis/3.0/system/callbacks`|
|
||
|---|---|
|
||
|
||
|`02`|`{`|
|
||
|---|---|
|
||
|
||
|`03`|`"id"``: 0,`|
|
||
|---|---|
|
||
|
||
|`04`|`"description"``:` `"maxLength = 100"``,`|
|
||
|---|---|
|
||
|
||
|`05`|`"url"``:` `"Sample string"``,`|
|
||
|---|---|
|
||
|
||
|`06`|`"objectId"``: 0,`|
|
||
|---|---|
|
||
|
||
|`07`|`"type"``:` `"Sample string"``,`|
|
||
|---|---|
|
||
|
||
|`08`|`"level"``:` `"Sample string"``,`|
|
||
|---|---|
|
||
|
||
|`09`|`"memberId"``: 0,`|
|
||
|---|---|
|
||
|
||
|`10`|`"inactiveFlag"``:` `"false"``,`|
|
||
|---|---|
|
||
|
||
|`11`|`"_info "``: {` `"lastUpdated"``:` `""``,` `"updatedBy"``:` `""` `}`|
|
||
|---|---|
|
||
|
||
|`12`|`}`|
|
||
|---|---|
|
||
|
||
### Testing Callbacks
|
||
|
||
#### Webhook.Site
|
||
|
||
When testing the ConnectWise PSA callbacks there are a number of useful browser-based tools. One of note is [https://webhook.site](https://webhook.site/ "https://webhook.site").
|
||
|
||
Simply use the New button to create a URL and then the Copy URL button to save the URL generated to your clipboard and add this as your ConnectWise PSA callback URL.
|
||
|
||
```
|
||
https://webhook.site/xxxxxxx-xxxx-xxxx-af13-855ab85aebae
|
||
```
|
||
|
||
### When Callbacks Fail to POST to Target Host
|
||
|
||
When a callback receives an error when attempting to POST the callback payload to the host specified in the callback URL, ConnectWise PSA will retry the POST for any 404, 409, 419, or 429 error responses. ConnectWise PSA retries twice, once two seconds after the initial POST attempt and again four seconds after the first retry attempt. Requests will timeout after five seconds.
|
||
|
||
The system counts how many consecutive days the callback fails, and after three consecutive days of failed attempts, ConnectWise PSA will disable the callback
|
||
|
||
Any 2xx response is considered successful.
|
||
|
||
For partners with an on-premise instance of ConnectWise PSA, when troubleshooting why your callback POSTs are receiving error response from the remote host, logs for the service are found on the ConnectWise PSA frontend server at C:\\Program Files\\ConnectWise\\ApiCallbackService\\logs\\server.log
|
||
|
||
To enable verbose logging, change the minlevel value to minlevel=”Info” in the C:\\Program Files\\ConnectWise\\ApiCallbackService\\ApiCallbackService.exe.nlog
|
||
|
||
### Verifying the Callback Source
|
||
|
||
Callbacks contain a key\_url in the metadata section that can be used to verify the source of the callback. The key\_url returns the signing key which then can be used in conjunction with the below code sample and the x-content-signature.
|
||
|
||
|`1`|`using` `(var sha =` `new` `SHA256Managed())`|
|
||
|---|---|
|
||
|
||
|`2`|`{`|
|
||
|---|---|
|
||
|
||
|`3`|`var hash = sha.ComputeHash(Encoding.UTF8.GetBytes(sharedSecretKey));`|
|
||
|---|---|
|
||
|
||
|`4`|`using` `(var hmac =` `new` `HMACSHA256(hash))`|
|
||
|---|---|
|
||
|
||
|`5`|`{`|
|
||
|---|---|
|
||
|
||
|`6`|`return` `Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(jsonPayload)));`|
|
||
|---|---|
|
||
|
||
|`7`|`}`|
|
||
|---|---|
|
||
|
||
|`8`|`}`|
|
||
|---|---|
|
||
|
||
### Callback Changelog
|
||
|
||
|**Supported Version**|**Changes**|
|
||
|---|---|
|
||
|ConnectWise PSA 2020.2|Added callbacks for Configurations|
|
||
|ConnectWise PSA 2016.6|Added callbacks for Invoice
|
||
Added callbacks for Projects
|
||
Added callbacks for Activities|
|
||
|ConnectWise PSA 2016.5|Company Callbacks: Added Status and Type levels
|
||
Contact Callbacks: Added Type level
|
||
Ticket Callbacks: Added levels for tracking Project Tickets|
|
||
|ConnectWise PSA 2016.4|Added callbacks for Opportunities|
|
||
|ConnectWise PSA 2016.3|Added callbacks for Companies and Contacts|
|
||
|ConnectWise PSA 2015.6|Added callbacks for Tickets| |