Files
resolutionflow/docs/connectwise/best-practices/Bundled-Requests.md
chihlasm 46865882c6 feat: ConnectWise PSA integration (#106)
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.
2026-03-15 01:45:35 -04:00

381 lines
6.1 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
1. Last updated
Mar 31, 2023
2. [Save as PDF](https://developer.connectwise.com/@api/deki/pages/1350/pdf/Bundled%2bRequests.pdf "Export page as a PDF")
#### Purpose
The Bundle endpoint is so that the end users can post multiple distinct requests at the same time. An example is if you need data from a number of endpoints for a single screen, instead of making each individual call you would bundle them together and make one request. This will save time and bandwidth.
## Request
When sending a bundled request to the server, you will send an array of the same objects you would send in a singular request.
|`01`|`{`|
|---|---|
|`02`|`"requests"``: [`|
|---|---|
|`03`|`{`|
|---|---|
|`04`|`"Version"``:` `"2019.3"``,`|
|---|---|
|`05`|`"SequenceNumber"``:` `1``,`|
|---|---|
|`06`|`"ResourceType"``:` `"ticket"``,`|
|---|---|
|`07`|`"ApiRequest"``: {`|
|---|---|
|`08`|`"Filters"``: {`|
|---|---|
|`09`|`"conditions"``:` `"summary like '%a%' and status/name like '%new%'and board/name='Help Desk'"`|
|---|---|
|`10`|`},`|
|---|---|
|`11`|`"Page"``: {`|
|---|---|
|`12`|`"page"``:` `1``,`|
|---|---|
|`13`|`"pageSize"``:` `1000`|
|---|---|
|`14`|`}`|
|---|---|
|`15`|`}`|
|---|---|
|`16`|`},`|
|---|---|
|`17`|`{`|
|---|---|
|`18`|`"Version"``:` `"2019.2"``,`|
|---|---|
|`19`|`"SequenceNumber"``:` `1``,`|
|---|---|
|`20`|`"ResourceType"``:` `"Company"``,`|
|---|---|
|`21`|`"ApiRequest"``: {`|
|---|---|
|`22`|`"Filters"``: {`|
|---|---|
|`23`|`"conditions"``:` `"companyName = 'Connectwise'"``,`|
|---|---|
|`24`|`"childConditions"``:` `""``,`|
|---|---|
|`25`|`"customFieldConditions"``:` `""`|
|---|---|
|`26`|`},`|
|---|---|
|`27`|`"Page"``: {`|
|---|---|
|`28`|`"pageSize"``:` `25``,`|
|---|---|
|`29`|`"pageId"``:` `2`|
|---|---|
|`30`|`},`|
|---|---|
|`31`|`"Id"``:` `1``,`|
|---|---|
|`32`|`"ParentId"``:` `2``,`|
|---|---|
|`33`|`"GrandParentId"``:` `3`|
|---|---|
|`34`|`}`|
|---|---|
|`35`|`},`|
|---|---|
|`36`|`{`|
|---|---|
|`37`|`"Version"``:` `"2019.2"``,`|
|---|---|
|`38`|`"SequenceNumber"``:` `2``,`|
|---|---|
|`39`|`"ResourceName"``:` `"Member"``,`|
|---|---|
|`40`|`"ApiRequest"``: {`|
|---|---|
|`41`|`"Id"``:` `1``,`|
|---|---|
|`42`|`"ParentId"``:` `2``,`|
|---|---|
|`43`|`"GrandParentId"``:` `3``,`|
|---|---|
|`44`|`"Filters"``: {`|
|---|---|
|`45`|`"conditions"``:` `"memberName = 'John Smith'"``,`|
|---|---|
|`46`|`"childConditions"``:` `""``,`|
|---|---|
|`47`|`"customFieldConditions"``:` `""`|
|---|---|
|`48`|`},`|
|---|---|
|`49`|`"Page"``: {`|
|---|---|
|`50`|`"page"``:` `1``,`|
|---|---|
|`51`|`"pageSize"``:` `25`|
|---|---|
|`52`|`}`|
|---|---|
|`53`|`}`|
|---|---|
|`54`|`}`|
|---|---|
|`55`|`]`|
|---|---|
|`56`|`}`|
|---|---|
### Example: Line Items from PO
This example is a GET on Line Items for purchase order 1.  Note the ParentId specifies the purchase order recId.
|`01`|`{`|
|---|---|
|`02`|`"requests"``:`|
|---|---|
|`03`|`[`|
|---|---|
|`04`|`{`|
|---|---|
|`05`|`"Version"``:``"2019.5"``,`|
|---|---|
|`06`|`"SequenceNumber"``:``1``,`|
|---|---|
|`07`|`"ResourceType"``:``"purchaseorderlineitem"``,`|
|---|---|
|`08`|`"ApiRequest"``:{`|
|---|---|
|`09`|`"Filters"``:`|
|---|---|
|`10`|`{`|
|---|---|
|`11`|`"conditions"``:``""``,`|
|---|---|
|`12`|`"childConditions"` `:` `""``,`|
|---|---|
|`13`|`"customFieldConditions"``:` `""`|
|---|---|
|`14`|`},`|
|---|---|
|`15`|
|---|
|`16`|`"Page"``: {`|
|---|---|
|`17`|`"page"` `:` `1``,`|
|---|---|
|`18`|`"pageSize"``:` `1000`|
|---|---|
|`19`|`},`|
|---|---|
|`20`|`"parentId"``:``1`|
|---|---|
|`21`|`}`|
|---|---|
|`22`|`}`|
|---|---|
|`23`|`]`|
|---|---|
|`24`|`}`|
|---|---|
## Response
The response object that is returned is slightly different from what they normally get back from the singular endpoints. This is because we need to track the success status of each object individually. Because of this, there will be a wrapper class around each returned object that will have status information.
Furthermore, since each record may have different statuses, we will respond with different status codes depending on what the outcomes are.
The wrapper will have 5 properties:
- success: This property is a boolean that indicates if the response was a success or an error occurred
- sequenceNumber: This is the sequence number passed in with the array. This is so you can map the returned object back to the original sent-in object so you can sync ids and all other information
- statusCode: This will be filled in with what the status code would have been if the user had called the individual endpoint (e.g. 200, 400, 403)
- error: If success is false, this will be populated with the error response that you would have received if you called the individual endpoint; Else this will be null and not returned.
- data: If success is true, this will be populated with the returned object as if the called the individual endpoint; Else this will be null and not returned
|`01`|`{`|
|---|---|
|`02`|`"results"``: [`|
|---|---|
|`03`|`{`|
|---|---|
|`04`|`"sequenceNumber"``:` `1``,`|
|---|---|
|`05`|`"resourceType"``:` `"Company"``,`|
|---|---|
|`06`|`"entities"``: [`|
|---|---|
|`07`|`{`|
|---|---|
|`08`|`"record"``:` `"Company1data"`|
|---|---|
|`09`|`},`|
|---|---|
|`10`|`{`|
|---|---|
|`11`|`"record2"``:` `"Company2data"`|
|---|---|
|`12`|`}`|
|---|---|
|`13`|`],`|
|---|---|
|`14`|`"count"``:` `2``,`|
|---|---|
|`15`|`"success"``:` `true``,`|
|---|---|
|`16`|`"statusCode"``:` `200`|
|---|---|
|`17`|`},`|
|---|---|
|`18`|`{`|
|---|---|
|`19`|`"sequenceNumber"``:` `2``,`|
|---|---|
|`20`|`"resouceType"``:` `"ServiceNote"``,`|
|---|---|
|`21`|`"count"``:` `0``,`|
|---|---|
|`22`|`"success"``:` `false``,`|
|---|---|
|`23`|`"statusCode"``:` `404``,`|
|---|---|
|`24`|`"error"``: {`|
|---|---|
|`25`|`"code"``:` `"NotFound"``,`|
|---|---|
|`26`|`"message"``:` `"ServiceNote123notfound"`|
|---|---|
|`27`|`}`|
|---|---|
|`28`|`}`|
|---|---|
|`29`|`],`|
|---|---|
|`30`|`"_info"``: {`|
|---|---|
|`31`|`"failure"``:` `"1"``,`|
|---|---|
|`32`|`"success"``:` `"1"``,`|
|---|---|
|`33`|`"total"``:` `"2"`|
|---|---|
|`34`|`}`|
|---|---|
|`35`|`}`|
|---|---|