Try our GraphQL Playground
We've included some static documentation below, however GraphQL APIs are traditionally represented through interactive playgrounds. HOVER GraphQL Playground
Introduction
A contractor generates a proposal for the customer based on a selected salesOpportunity
or estimateGroup
. When a proposal is created, a corresponding PDF is generated. This PDF can be shared with the customer via an embedded on screen signature or shared via email. When a proposal document PDF is created or updated, HOVER sends a webhook with the event, order document id, state, and timestamp.
Webhooks
project-management-proposal-document-state-changed
Event
project-management-proposal-document-state-changed
EventWhen a project management proposal document has been created, you will receive a webhook with the following post body.
Why would I use this?
Receiving an event notifying you that a proposal document is completed allows you to look at the ID of the document to hit our API to download it to , maybe, your CRM, or to your sales persons personal computer to show a customer.
{
"event": "project-management-proposal-document-state-changed",
"project_management_proposal_document_id": "d69021ae-2ebb-457d-b645-b70e6e26a903",
"state": "complete"
}
project-management-signature-request-state-changed
Event
project-management-signature-request-state-changed
EventWhen a project management signature request has been created, you will receive a webhook with the following post body. The signed_at field value is seconds since the epoch. Please note that a project-management-signature-request-state-changed
event signed_at
will only be sent when the state is signed
or complete
.
{
"event": "project-management-signature-request-state-changed",
"project_management_signature_request_id": "b37dfabb-c0f4-4d75-a753-450f819e27af",
"project_management_proposal_document_id": "ea253901-01a3-4b43-94f1-98802ae8496b",
"state": "signed",
"signed_at": 1598555054
}
Signed Proposals
Once a proposal is signed, the proposal document PDF gets updated with the customer signature. When a proposal document PDF is created or updated, HOVER sends a webhook with the event, proposal document ID, state, and timestamp.
This webhook will also be used to indicate when a SignatureRequest was made, based on the signedAt
timestamp and state fields.
Queries
projectManagementProposalDocuments
projectManagementProposalDocuments
This query will return all the proposal documents associated with an estimate.
{
projectManagementProposalDocuments(estimateGroupId: {estimate_group_id}) {
nodes{
id
createdAt
updatedAt
signatureRequest {
createdAt
signedAt
}
pdf{
redirectUrl
}
}
}
}
{
"data": {
"projectManagementProposalDocuments": {
"nodes": [
{
"id": "e0bf7161-3812-4c8d-8d7f-bb11237bb1b7",
"createdAt": "2020-06-25T08:54:08Z",
"updatedAt": "2020-06-25T08:55:16Z",
"signatureRequest": {
"createdAt": "2020-06-25T08:54:25Z",
"signedAt": null
},
"pdf": {
"redirectUrl": "redirectUrl"
}
},
// ... other documents ... //
]
}
}
}
curl -X POST "https://graph.hover.to/graphql" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d '{"query": "{ projectManagementProposalDocuments(estimateGroupId: \"estimate_group_id\") { nodes { id createdAt updatedAt signatureRequest { createdAt signedAt } pdf { redirectUrl } } } }"}'
Request:
Method: POST
URL: https://graph.hover.to/graphql
Headers:
Content-Type: application/json
Authorization: Bearer YOUR_ACCESS_TOKEN
Body:
Type: Raw (JSON)
Content:
{
"query": "{ projectManagementProposalDocuments(estimateGroupId: \"estimate_group_id\") { nodes { id createdAt updatedAt signatureRequest { createdAt signedAt } pdf { redirectUrl } } } }"
}
Filtering Arguments
You can specify arguments when querying proposal documents. These arguments are entered in the query as shown below:
projectManagementProposalDocuments(last: 30, state: COMPLETE)
Argument | Description |
---|---|
after | Returns the elements in the list that come after the specified cursor |
before | Returns the elements in the list that come before the specified cursor |
first | Returns the first n elements from the list |
last | Returns the last n elements from the list |
salesOpportunityId | Only return records for this sales opportunity |
estimateGroupId | Only return records for this estimate group |
state | Return documents at given state |
Get a Proposal Document Details
This example query using projectManagementProposalDocuments
will return all available details of a specific proposal document.
{
projectManagementProposalDocument(id: proposal_document_id) {
id
createdAt
userId
customerName
customerEmail
state
totalPrice
pdf {
redirectUrl
}
signatureRequest {
createdAt
requestType
signedAt
state
}
estimateGroup {
salesOpportunity {
id
createdAt
updatedAt
soldEstimateGroupId
productionList {
id
}
}
jobId
orgId
estimates {
name
tradeType
active
userId
discount
discounts {
name
value
discountType
}
}
}
}
}
{
"data": {
"projectManagementProposalDocument": {
"id": "e0bf7161-3812-4c8d-8d7f-bb11237bb1b7",
"createdAt": "2020-06-25T08:54:08Z",
"userId": 549941,
"customerName": "John Smith",
"customerEmail": "[email protected]",
"state": "COMPLETE",
"totalPrice": 31851.32333,
"pdf": {
"redirectUrl": "redirectUrl"
},
"signatureRequest": {
"createdAt": "2020-06-25T08:54:25Z",
"requestType": "EMBED",
"signedAt": null,
"state": "COMPLETE"
},
"estimateGroup": {
"salesOpportunity": {
"id": 17659,
"createdAt": "2020-06-25T08:52:02Z",
"updatedAt": "2020-06-25T09:09:00Z",
"soldEstimateGroupId": "228457",
"productionList": {
"id": 6943
}
},
"jobId": "2210684",
"orgId": "301438",
"estimates": [
{
"name": "GAF Timberline American Harvest (Roof)",
"tradeType": "ROOF",
"active": false,
"userId": 549941,
"discount": 0,
"discounts": []
},
{
"name": "GAF - Grand Sequoia (Roof)",
"tradeType": "ROOF",
"active": false,
"userId": 549941,
"discount": 0,
"discounts": []
},
{
"name": "Standard (Skylights)",
"tradeType": "SKYLIGHTS",
"active": false,
"userId": 549941,
"discount": 0,
"discounts": []
},
{
"name": "Custom (Skylights)",
"tradeType": "SKYLIGHTS",
"active": false,
"userId": 549941,
"discount": 0,
"discounts": []
},
{
"name": "Vinyl (Windows)",
"tradeType": "WINDOWS",
"active": false,
"userId": 549941,
"discount": 0,
"discounts": []
},
{
"name": "Custom (Windows)",
"tradeType": "WINDOWS",
"active": false,
"userId": 549941,
"discount": 0,
"discounts": []
},
{
"name": "Wood & Plastic (Door)",
"tradeType": "DOOR",
"active": false,
"userId": 549941,
"discount": 0,
"discounts": []
},
{
"name": "Specialty (Door)",
"tradeType": "DOOR",
"active": false,
"userId": 549941,
"discount": 0,
"discounts": []
},
{
"name": "Gutters (With Roof Discount)",
"tradeType": "GUTTERS",
"active": false,
"userId": 549941,
"discount": 0,
"discounts": []
},
{
"name": "Gutters + Toppers (with discount)",
"tradeType": "GUTTERS",
"active": false,
"userId": 549941,
"discount": 0,
"discounts": []
},
{
"name": "Standard (Fascia)",
"tradeType": "FASCIA",
"active": true,
"userId": 549941,
"discount": 6.15,
"discounts": [
{
"name": "promo",
"value": 10,
"discountType": "PERCENTAGE"
}
]
},
{
"name": "GAF Timberline HD (Roof)",
"tradeType": "ROOF",
"active": true,
"userId": 549941,
"discount": 2731.52,
"discounts": [
{
"name": "promo",
"value": 10,
"discountType": "PERCENTAGE"
}
]
},
{
"name": "Gutters",
"tradeType": "GUTTERS",
"active": true,
"userId": 549941,
"discount": 1566.11,
"discounts": [
{
"name": "Gutters Special",
"value": 25,
"discountType": "PERCENTAGE"
},
{
"name": "promo",
"value": 10,
"discountType": "PERCENTAGE"
}
]
}
]
}
}
}
}
curl -X POST "https://graph.hover.to/graphql" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d '{"query": "{ projectManagementProposalDocument(id: \"proposal_document_id\") { id createdAt userId customerName customerEmail state totalPrice pdf { redirectUrl } signatureRequest { createdAt requestType signedAt state } estimateGroup { salesOpportunity { id createdAt updatedAt soldEstimateGroupId productionList { id } } jobId orgId estimates { name tradeType active userId discount discounts { name value discountType } } } } }"}'
Request:
Method: POST
URL: https://graph.hover.to/graphql
Headers:
Content-Type: application/json
Authorization: Bearer YOUR_ACCESS_TOKEN
Body:
Type: Raw (JSON)
Content:
{
"query": "{ projectManagementProposalDocument(id: \"proposal_document_id\") { id createdAt userId customerName customerEmail state totalPrice pdf { redirectUrl } signatureRequest { createdAt requestType signedAt state } estimateGroup { salesOpportunity { id createdAt updatedAt soldEstimateGroupId productionList { id } } jobId orgId estimates { name tradeType active userId discount discounts { name value discountType } } } } }"
}
Proposal Field Index
Field | Description |
---|---|
id | Proposal document ID |
createdAt | Timestamp of when the document was first generated |
customerName | Name of the customer |
customerEmail | Email of the customer |
state | Current state of the proposal, can be one of:CREATED , QUEUED , REQUESTED , SIGNED , COMPLETE , FAILED , CANCELLED , DECLINED |
tradeType | The estimated trade types of the proposal (roof, gutters, siding, etc.) |
requestType | The format of the proposal, can be one of:embedded : the customer signed the proposal onscreen.shared : the proposal was sent via email |
signedAt | Timestamp when the proposalDocument was signed |
totalPrice | The total price, including discounts, on the proposal. |
discount | Total discount value applied to a particular trade. |
redirectUrl | Non-expiring URL to the proposal PDF. Requires authentication to view. |