Accounting Extension

Introduction

On this page, we walk you through the steps of getting your integration working with the HubSpot accounting extension

Create your app definition on HubSpot

In order for your integration to connect to a HubSpot user's account, you must create an app definition on HubSpot for it.  Here, you enter details such as the logo and text to be shown to the HubSpot user when your integration attempts to make an initial connection to their account, and it also defines what permissions (scopes) your integration needs in the user's HubSpot account.

There is an overview on how to use the HubSpot developer tools, but the steps to get up and running are:

  1. Get a developer account
  2. Create an application definition on your developer account
  3. You will need to modify the application that you created, and add accounting as a scope used.  If you plan to support contact syncing with HubSpot, you should also add the contacts scope.

Connecting to a HubSpot user's account

OAuth

To connect and gain access to a HubSpot user' account, your integration needs to initiate an OAuth connect request to HubSpot. See Working with OAuth for more information on how to initiate the connect to HubSpot.

User Account Details

After the OAuth connection with HubSpot is established, you need to make an additional call to the PUT /crm/v3/extensions/accounting/user-account endpoint to give us additional information about the user's account on your external accounting system.

The HubSpot accounting extension will make a number of webhook calls to your configured endpoints as part of the accounting features.  We send the account id of the user in your accounting system as part of these webhook calls, so that you know which account in your system we are dealing with.  Because of the way OAuth works, we don't know the account id of your user when a connection is made, so you need to make an additional call to provide this information.

Call the PUT https://api.hubapi.com/crm/v3/extensions/accounting/user-account endpoint with the OAuth access token that you just received, providing us with information about the account in your system that was connected with that  Auth token. An example payload would be:

JSON
// Example account details
{
  "accountId": "acct-app-123",
  "accountName": "My Coffee Shop Accounts",
  "currencyCode": "USD"
}

You can do the basic CRUD operations using the /user-accounts API. When a customer installs/uninstalls your app, you need to call this API and let us know which accounts are available/no longer available to use.

Authentication

There are 2 ways to authenticate API requests made to HubSpot:

  1. API Key. Your developer API key is used when managing settings related to your HubSpot apps through the API (the /settings endpoints for the accounting extension)
  2. OAuth token.  You need to use an oauth token for any request made on behalf of a HubSpot user (the /callback and /user-accounts endpoints for the accounting extension).  Note that you must ask for the accounting scope when requesting an oauth token for use with the accounting extension.

Read the Authentication documentation for more information.

Webhooks

When HubSpot send a request to your server to perform an action or retrieve information, it does this in the form of a webhook call to your endpoints.  The next sections describe what the call flow is for webhook calls, and how to configure the endpoints HubSpot should call on your server

Call Flow

Below is a graph that describes the general call flow

plantuml

The steps of the call flow are as follows:

1. Receive the webhook from HubSpot

You'll start receiving API requests to your configured URLs. The body of each request will be a JSON payload. To ensure that the requests you're getting at your webhook endpoint are actually coming from HubSpot, we populate a X-HubSpot-Signature header with a SHA-256 hash of the concatenation of the client secret for your application and the request body we're sending. For more details on validating the webhook signature, view this page.

2. Acknowledge the webhook

Your server receives the webhook, and validates that the JSON payload is well formed that the request is signed correctly.  Your server should return a 200 status code if the request is valid, or 400 if it is invalid.

Note that you should acknowledge the webhook before your server actually performs the action requested.

3. Send result of action to HubSpot

When your server has completed the requested action, it will send the result to HubSpot.

Each webhook request payload sent from HubSpot contains a metadata object which contains a callbackUrl field.  You should send the result by POSTing to the callbackUrl endpoint.  Make sure to use the OAuth access token of the HubSpot user account that is linked to the accountId sent in the request.

4. HubSpot acknowledges the result

HubSpot will respond with a 200 status code if the result is received and validated, or 400 if there was an error.

Sending an error as a result to HubSpot

Sometimes, HubSpot may send a webhook request that you deem invalid (for example, HubSpot sends a request to create a customer that already exists).  In such cases, you would send the error response to the callbackUrl.

Note that all responses to the callback endpoints should contain a "@result" field, that has a value of either "OK" or "ERR', which indicates if the response represents a success or failure of the requested task.

Error Response Structure

All the callback endpoints take the same error JSON format, an object that contains 5 fields:

  • @result: (string) for an error, this will have the value "ERR"
  • message: (string) a text description of the error that occurred.
  • category: (string) the type of error. One of the following values:
    • CUSTOMER_ALREADY_EXISTS: A customer cannot be created because they already exist
    • VALIDATION_INVALID_INPUT: A text field contains an invalid character or symbol.  For example, a customer name contains a ™ symbol which you do not support.
    • LICENSE_EXPIRED: The request was rejected because the customer's trial/license on your system has expired.
    • TAX_INFO_MISSING: There was required tax information missing, and the operation cannot be completed.
    • OBJECT_ALREADY_EXISTS: The object already exists.
    • CONNECTED_ACCOUNT_ERROR: The request was rejected because there was a problem with the account (eg. the account no longer exists, doesn't have permissions to do the requested action).
    • VALIDATION_ERROR: The input failed validation (for a reason not available in one of these error categories).  For example, the request you received was invalid JSON.
    • UNEXPECTED_ERROR: Represents a server error in your system (e.g 500 http status code).
    • INSUFFICIENT_INVENTORY: There are not enough items in stock to satisfy the number in the invoice. You should enter values in the context field to identify which product(s) in the invoice have insufficient inventory, and include the remaining inventory number. For example, if the product with id shoe-123 only had 3 items remaining and the invoice line item for shoe-123 had a requested quantity of 5, you could return the following error:

      {
      "@result": "ERR",
      "message": "There is not enough inventory to satisfy the requested amounts.",
      "category": "INSUFFICIENT_INVENTORY",
      "timestamp": "2020-03-31T10:15:30Z",
      "context": {
      "shoe-123": ["3"]
      }
      }
  • timestamp: (string) either an ISO 8601 representation of the datetime that the error occurred, or in epoch milliseconds.
  • context: (map[string, string[]])  optional additional context about the error condition, which will be used by HubSpot to build more actionable error messages for human users. See INSUFFICIENT_INVENTORY for an example of this fields use.

Here is an example error response:

JSON
// Error format
{
  "@result": "ERR",
  "message": "The customer you are trying to create already exists.",
  "category": "CUSTOMER_ALREADY_EXISTS",
  "timestamp": "2020-03-31T10:15:30Z"
}

Configuring Webhook Endpoints

In order for HubSpot to know which endpoints to send webhooks to on your server, you need to configure the "settings" for your application. These settings contain the "accounting features" your app supports as well as the URLs of the endpoints for those features that HubSpot should send webhooks to; there is a different endpoint setting for each action that HubSpot makes.

Accounting Features

There are several features available to users of your app when it is configured with the Accounting Extension. You do not need to support all features however you do need to specify which features you support.

Primary features

Your app needs to supportat least oneof the following primary features:

  • Invoice creation- A user can create an invoice in your accounting system from HubSpot
  • Invoice import- A user can import invoices into HubSpot from your accounting system

Invoice creation secondary features

If your app supports invoice creation, there are secondary optional features that you can also support:

  • Customer creation - A customer can be created as part of the invoice creation
  • Taxes - Taxes can be searched
  • Exchange rates - Exchanges rate between two currencies can be requested
  • Payment terms - Payment terms can be retrieved
  • Invoice comments - Comments can be added to the invoice to be created
  • Invoice Discounts - Indicates if invoice-level discounts can be added to invoices. If invoice discounts are not supported, then we will not allow the creation of invoices from quotes.  This is because quotes in HubSpot may contain discounts, and if it is not possible to include that discount information in created invoices, incorrect information might occur.

NOTE: If your app does not support invoice creation then it is not possible to enable any of these secondary features as they are only applicable in the context of invoice creation.

Configuring app "webhook" settings

You must specify the features your app supports as well as the corresponding URLs for those features.

https://api.hubapi.com/crm/v3/extensions/accounting/settings

Send a PUT request to /settings with the required body. You can update (PUT) or view (GET) your settings at any point.

Template Urls

We display deep links to customers in the HubSpot CRM. In order to display a link correctly and quickly, we ask integrators to provide template urls.

Possible tokens are: 

JSON
ACCOUNT_NAME
ACCOUNT_ID
INVOICE_ID
CUSTOMER_ID
PRODUCT_ID

Dummy Endpoints

HubSpot requires that an endpoint URL is specified for every enabled feature in the settings as well as required endpoint. However, when you are initially integrating, you may not yet have an implementation of each endpoint. Our advice would be to just fill in a dummy value (such as http://example.com) until you are ready to implement the endpoint.

Required URLs

The following URLs must be set:

  • getInvoiceUrl
  • getInvoicePdfUrl
  • searchCustomerUrl

Feature URLs

The following is a list of features along with their associated endpoint URLs.

  • Invoice creation - createInvoiceUrl, searchProductUrl
  • Invoice import - searchInvoiceUrl
  • Customer creation - createCustomerUrl
  • Taxes - searchTaxUrl
  • Exchange rates - exchangeRateUrl
  • Payment terms - getTermsUrl
  • Invoice comments - No URL associated with this feature
  •  Invoice Discounts - No URL associated with this feature

Webhook Endpoint Implementation Order

If you want to implement your webhook endpoints one at a time, then you should first implement the required URLs, in any order.

  • getInvoiceUrl
  • getInvoicePdfUrl
  • searchCustomerUrl

Once these are completed, you can move on to implementing your supported feature URLs.

Invoice Import (Primary feature)

If your app is not going to support Invoice Import then you can skip this section. Otherwise you must implement the following endpoint URL:

  • searchInvoiceUrl

Invoice Creation (Primary feature)

If your app will support Invoice Creation then you should implement the required URLs for this primary feature in the following order (this is the order the endpoints will be called in when creating an invoice)

  1. searchProductUrl
  2. createInvoiceUrl

Invoice Creation (Secondary features)

You can support all, none or some of the following secondary features. Here is the order they would be implemented in if all were supported:

  1. searchTaxUrl
  2. exchangeRateUrl
  3. getTermsUrl
  4. createCustomerUrl
  5. createInvoiceUrl

Testing your integration on HubSpot

Create a test HubSpot account

The first thing you need to do is create a test HubSpot account from within your developer account. The test account will allow you to test and use most HubSpot features, including your accounting integration.

Find out more at How do i create a test account?

Installing your app to your test account

Now that you have created a test HubSpot account, you need to install your app in that test account.  You can verify that the app has been installed on you test account by going to the connected apps page

Please read Authorizing and installing an app for more information

Create an Invoice

Invoices in HubSpot are created from deals. In HubSpot, a deal represents an ongoing transaction that a sales team is pursuing with a contact or company.  A deal can be created in the UI by selection "Sales" from the top nav, selecting "Deals" and then pressing the "Create deal" button.  Once you have created a deal, you will be automatically brought to the overview screen of the deal you just created.  On the right-hand side of this screen, you will see an "Invoices" section.  Click on "Create invoice" and enter the details of invoice you wish to create. You should be receiving webhook calls from HubSpot for the various stages of the invoice creation flow.

Webhook Endpoints

Below are the webhook endpoints that can be configured with a call to /settings.  The JSON payload send to each webhook endpoint and the expected callback format are described.  See the endpoints tab for more specific information on individual callback endpoints.

getInvoiceUrl (Required)

A URL that specifies the endpoint where invoices can be retrieved.

1) Request to your service JSON:

JSON
// Get Invoices Request
{
  "invoiceIds": List<string>
  "accountId": string,
  "metadata": { 
    "requestId": string 
  }
}

Example JSON

JSON
// Example Request
{
  "invoiceIds": [
    "inv-1",
    "inv-2"
  ],
  "metadata": {
    "requestId": "test-req-id"
  },
  "accountId": "123146316464684"
}

2) Response to HubSpot:

    200 (no body)

3) Request to HubSpot callback endpoint (/callback/invoices/{requestId}) JSON:

JSON
// Customer Create Response
{
  "@result": "OK",
  "invoices": [
    {
      "invoiceId": string,
      "invoiceNumber": string,
      "currency": string,
      "amountDue": number,
      "balance": number,
      "dueDate": string,
      "customerId": string,
      "customerName": string,
      "invoiceLink": string,
      "status": string
    }
  ]
}

The status field is a string which should have one of the following values:

  • CREATED: Waiting to be sent to the customer.
  • SENT: The invoice has been sent to customer.
  • PAID: Partial payment has been received for the invoice.
  • CLOSED: The invoice has been paid in full.
  • OVERDUE: The invoice is overdue - the due date is in the past.
  • VOIDED: The invoice has been voided.

Example JSON

JSON
// Example Response
{
  "@result": "OK",
  "invoices": [
    {
      "invoiceId": "inv-1",
      "invoiceNumber": "INV-123",
      "currency": "USD",
      "amountDue": 100.5,
      "balance": 50,
      "dueDate": "2020-03-31",
      "customerId": "cust-123",
      "customerName": "John Smith",
      "invoiceLink": "https://myapp.com/invoices/1243a2",
      "status": "OVERDUE"
    }
  ]
}

4) Response to your service JSON:

    200 or 400 with error info

getInvoicePdfUrl (Required)

A URL that specifies the endpoint where an invoice PDF can be retrieved.

1) Request to your service JSON:

JSON
// Example Request
{
  "invoiceId": "inv-1",
  "metadata": {
    "requestId": "test-req-id"
  },
  "accountId": "123146316464684"
}

2) Response to HubSpot:

    200 (no body)

3) Request to HubSpot callback endpoint (/callback/invoice-pdf/{requestId}) JSON:

JSON
// Response Structure
{
  "@result": "OK",
  "invoice": string (format: byte)
}

The invoice field is a BASE64 encoded string of the bytes of the invoice PDF.

Example JSON:

JSON
// Example Response
{
  "@result": "OK",
  "invoice": "U3dhZ2dlciByb2Nrcw=="
}

4) Response to your service JSON:

    200 or 400 with error info

searchCustomerUrl (Required)

A URL that specifies the endpoint where a customer search can be performed.

1) Request to your service JSON:

JSON
// searchCustomerUrl
{
  "pageNumber": Optional<int>,
  "pageSize": Optional<int>,
  "searchRequests": [
    {
      "query": string,
      "fieldTypes": [string]
    }
  ],
  "metadata": {
    "requestId": string
  },
  "accountId": string
}

Where there are multiple entries in searchRequests, they should be treated as OR Case sensitivity should follow your platform's default. If it is possible in your system to have 2 customers, John and JOHN, then searches should be case sensitive. If not, they should be case insensitive.

  • pageNumber is the page number of results to return from the search. This allows for paginations in the HubSpot UI. pageNumber starts at 1.
  • pageSize is the maximum number of results to return from the search.
  • fieldTypes is a list of strings that described how to perform the search. The possible values are:
    • EMAIL: return customers whos email addresses contains the query string.
    • NAME: return customers whos name contains the query string.
    • ID: return customer(s) that have an id that match the query string. Only one id will be specified in the query string.

Example JSON

JSON
// example request
{
  "searchRequests": [
    {
      "query": "Amy",
      "fieldTypes": [
        "NAME", "EMAIL"
      ]
    },
    {
      "query": "Birds",
      "fieldTypes": [
        "EMAIL"
      ]
    }
  ],
  "metadata": {
    "requestId": "tests-req-id"
  },
  "accountId": "123146316464684"
}

2) Response to HubSpot:

    200 (no body)

3) Request to HubSpot callback endpoint (/callback/customer-search/{requestId}) JSON:

JSON
// request to hubspot 
{
  "@result": "OK",
  "customers": [
    {
      "id": int,
      "name": string,
      "emailAddress": string,
      "billingAddress": {
        "lineOne": Optional<string>,
        "city": Optional<string>,
        "countrySubDivisionCode": Optional<string>,
        "postalCode": Optional<string>,
        "country": Optional<string>
      }
    },
    ...
  ]
}

Example JSON

JSON
// example
{
  "@result": "OK",
  "customers": [
    {
      "id": "1",
      "name": "Amy's Bird Sanctuary",
      "emailAddress": "Birds@company.com",
      "billingAddress": {
        "lineOne": "4581 Finch St.",
        "city": "Bayshore",
        "countrySubDivisionCode": "CA",
        "postalCode": "94326",
        "country": null
      }
    },
    {
      "id": "58",
      "name": "Bobby",
      "emailAddress": "bobby@company.com"
    }
  ]
}

4) Response to your service JSON:

    200 or 400 with error info

searchInvoiceUrl (Required if Invoice Import feature is enabled)

A URL that specifies the endpoint where an invoice search can be performed.

1) Request to your service JSON:

JSON
// Search Taxes Request
{
  "request": {
    "queryType": Optional<{
      "fieldType": string (INVOICE_NUMBER|CUSTOMER_NAME),
      "queryValues": List<string>,
    }>,
    "orderBy": string (DUE_DATE),
    "orderDirection": string (ASC|DESC),
    "pageNumber": Optional<integer>,
    "pageSize": Optional<integer>
  },
  "accountId": string,
  "metadata": { 
    "requestId": string 
  }
}
  • pageNumber is the page number of results to return from the search. This allows for paginations in the HubSpot UI. pageNumber starts at 1.
  • pageSize is the maximum number of results to return from the search.
  • fieldType is a string that described how to perform the search. The possible values are:
    • INVOICE_NUMBER: return invoices whos number contains the query string.
    • CUSTOMER_NAME: return invoices for customers whos name contains the query string.

Example JSON:

JSON
// Example request
{
  "request": {
    "queryType": {
      "fieldType": "CUSTOMER_NAME",
      "queryValues": [
        "Amy"
      ],
    },
    "orderBy": "DUE_DATE",
    "orderDirection": "DESC",
    "pageNumber": 1,
    "pageSize": 20
  },
  "accountId": "123146316464684",
  "metadata": { 
    "requestId": "test-req-id" 
  }
}

2) Response to HubSpot:

    200 (no body)

3) Request to HubSpot callback endpoint (/callback/invoice-search/{requestId}) JSON:

JSON
// Search Invoice Response
{
  "@result": "OK",
  "invoices": [
    {
      "invoiceId": string,
      "invoiceNumber": string,
      "currency": string,
      "amountDue": number,
      "balance": number,
      "dueDate": string,
      "customerId": string,
      "customerName": string,
      "invoiceLink": string,
      "status": string
    }
  ]
}

Example JSON:

JSON
// Example response
{
  "@result": "OK",
  "invoices": [
    {
      "invoiceId": "inv-1",
      "invoiceNumber": "INV-123",
      "currency": "USD",
      "amountDue": 100.5,
      "balance": 50,
      "dueDate": "2020-03-31",
      "customerId": "cust-123",
      "customerName": "John Smith",
      "invoiceLink": "https://myapp.com/invoices/1243a2",
      "status": "OVERDUE"
    }
  ]
}

4) Response to your service JSON:

    200 or 400 with error info

searchProductUrl (Required if Invoice Creation feature is enabled)

A URL that specifies the endpoint where a product search can be performed.

1) Request to your service JSON:

JSON
// searchProductUrl
{
  "pageNumber": Optional<int>,
  "pageSize": Optional<int>,
  "searchRequests": [
    {
      "query": string,
      "fieldType": [string]
    }
  ],
  "metadata": {
    "requestId": string
  },
  "accountId": string
}

Where there are multiple entries in searchRequests, they should be treated as OR Case sensitivity should follow your platform's default. If it is possible in your system to have 2 products, "Shoe" and "SHOE", then searches should be case sensitive. If not, they should be case insensitive.

  • pageNumber is the page number of results to return from the search. This allows for paginations in the HubSpot UI. pageNumber starts at 1.
  • pageSize is the maximum number of results to return from the search.
  • fieldTypes is a list of strings that described how to perform the search. The possible values are:
    • NAME_FULL: return products whos name matches the query string.
    • NAME_PARTIAL: return products whos name contains the query string.
    • ID: return products that have ids that match the query string. Only one id will be specified in the query string.

Example JSON:

JSON
// Example request
{
  "searchRequests": [
    {
      "query": "PROD-1",
      "fieldType": "ID"
    },
    {
      "query": "Shoes",
      "fieldType": "NAME_PARTIAL"
    },
    {
      "query": "Cotton Pants",
      "fieldType": "NAME_FULL"
    }
  ],
  "metadata": {
    "requestId": "tests-req-id"
  },
  "accountId": "123146316464684"
}

2) Response to HubSpot:

    200 (no body)

3) Request to HubSpot callback endpoint (/callback/product-search/{requestId}) JSON:

JSON
// Product Search Response Structure
{
  "@result": "OK",
  "products": [
    {
      "unitPrice": {
        "amount": number,
        "taxIncluded": boolean
      },
      "taxExempt": boolean,
      "salesTaxType": {
        "code": string,
        "name": string
      },
      "name": string,
      "description": string,
      "id": string
    }
  ]
}

Example JSON:

JSON
// Product Search Response
{
  "@result": "OK",
  "products": [
    {
      "unitPrice": {
        "amount": 10.99,
        "taxIncluded": false
      },
      "taxExempt": false,
      "salesTaxType": {
        "code": "tax-1",
        "name": "Local Sales Tax"
      },
      "name": "Marketing Services",
      "description": "Website design, Online advertising and SEO.",
      "id": "PROD-1"
    },
    {
      "unitPrice": {
        "amount": 49.99,
        "taxIncluded": false
      },
      "taxExempt": false,
      "salesTaxType": {
        "code": "tax-1",
        "name": "Local Sales Tax"
      },
      "name": "Running Shoes",
      "description": "Special shoes aimed at running.",
      "id": "PROD-2"
    },
    {
      "unitPrice": {
        "amount": 20.99,
        "taxIncluded": false
      },
      "taxExempt": false,
      "salesTaxType": {
        "code": "tax-1",
        "name": "Local Sales Tax"
      },
      "name": "Cotton Pants",
      "description": "Cotton pants, a fashion favorite for a stylish look.",
      "id": "PROD-3"
    }
  ]
}

4) Response to your service JSON:

    200 or 400 with error info

searchTaxUrl (Required if Tax feature is enabled)

A URL that specifies the endpoint where a tax search can be performed.

1) Request to your service JSON:

JSON
// Search Taxes Request
{
  "searchRequest": {
    "fieldType": "NAME_PARTIAL",
    "query": string,
  },
  "accountId": string,
  "metadata": { 
    "requestId": string 
  }
}

fieldType will always be NAME_PARTIAL: return taxes who's name contains the query string.

Example JSON:

JSON
// Search Taxes Request
{
  "searchRequest": {
    "fieldType": "NAME_PARTIAL",
    "query": "VAT",
  },
  "accountId": "123146316464684",
  "metadata": { 
    "requestId": "test-req-id" 
  }
}

2) Response to HubSpot:

    200 (no body)

3) Request to HubSpot callback endpoint (/callback/tax-search/{requestId}) JSON:

JSON
// Response structure
{
  "@result": "OK",
  "taxes": [
    {
      "code": string,
      "percentage": number,
      "name": string
    }
  ]
}

Example JSON:

JSON
// Example response
{
  "@result": "OK",
  "taxes": [
    {
      "code": "tax-1",
      "percentage": 13.5,
      "name": "Reduced VAT Rate"
    }
  ]
}

4) Response to your service JSON:

    200 or 400 with error info

exchangeRateUrl (Required if Exchange Rate feature is enabled)

A URL that specifies the endpoint where exchange rates can be queried.

1) Request to your service JSON:

JSON
// Exchange Rate Request
{
  "sourceCurrencyCode": string,
  "targetCurrencyCode": string,
  "accountId": string,
  "metadata": { 
    "requestId": string 
  }
}

Example JSON:

JSON
// Example request
{
  "sourceCurrencyCode": "USD",
  "targetCurrencyCode": "EUR",
  "accountId": "123146316464684",
  "metadata": { 
    "requestId": "test-req-id" 
  }
}

2) Response to HubSpot:

    200 (no body)

3) Request to HubSpot callback endpoint (/callback/exchange-rate/{requestId}) JSON:

JSON
// Exchange Rate Response
{
  "@result": "OK",
  "sourceCurrencyCode": string,
  "targetCurrencyCode": string,
  "exchangeRate": number,
}

Example JSON:

JSON
// Example response
{
  "@result": "OK",
  "sourceCurrencyCode": "USD",
  "targetCurrencyCode": "EUR",
  "exchangeRate": 0.910847,
}

4) Response to your service JSON:

    200 or 400 with error info

getTermsUrl (Required if Payment Terms feature is enabled)

A URL that specifies the endpoint where payment terms can be retrieved. We will send a customerId field when making a request for payment terms for a particular customer. However, if the HubSpot user has chosen to create a new customer as part of creating a new invoice, then no customerId will be sent.

1) Request to your service JSON:

JSON
// Terms Request
{
  "accountId" : string,
  "customerId": Optional<string>,
  "metadata": { 
    "requestId": string 
  }
}

2) Response to HubSpot:

    200 (no body)

3) Request to HubSpot callback endpoint (/callback/terms/{requestId}) JSON:

JSON
// Terms Response
{
  "@result": "OK",
  "terms": [
    {
      "name": string,
      "id": string,
      "dueDays": integer
    }
  ]
}

Example JSON

JSON
//example JSON
{
  "@result": "OK",
  "terms": [
    {
      "name": "Net 30",
      "id": "net-30",
      "dueDays": 30
    }
  ]
}

4) Response to your service JSON:

    200 or 400 with error info

createCustomerUrl (Required if Customer Creation feature is enabled)

A URL that specifies the endpoint where a new customer can be created.

1) Request to your service JSON:

JSON
// Customer Create Request
{
  "customerCreationRequest": {
    "name": string,
    "emailAddress": string,
    "companyName": Optional<String>,
    "billingAddress":{
      "lineOne": Optional<String>,
      "city": Optional<String>,
      "countrySubDivisionCode": Optional<String>,
      "postalCode": Optional<String>,
      "country": Optional<String>
    }
  },
  "accountId": string,
  "metadata": { 
    "requestId": string 
  }
}

Example JSON

JSON
// Example Request
{
  "customerCreationRequest": {
    "name": "Amy's Bird Sanctuary",
    "emailAddress": "Birds@birds.com",
    "companyName": "HubSpot",
    "billingAddress": {
      "lineOne": "25 First Street",
      "city": "Cambridge",
      "countrySubDivisionCode": "MA",
      "postalCode": "02141",
      "country": "United States"
    }
  },
  "metadata": {
    "requestId": "test-req-id"
  },
  "accountId": "123146316464684"
}

2) Response to HubSpot:

    200 (no body)

3) Request to HubSpot callback endpoint (/callback/customer-create/{requestId}) JSON:

JSON
// Customer Create Response
{
  "@result": "OK",
  "id": string
}

Example JSON

JSON
// Example Response
{
  "@result": "OK",
  "id": "new-cust-123"
}

4) Response to your service JSON:

    200 or 400 with error info

createInvoiceUrl (Required if Invoice Creation feature is enabled)

A URL that specifies the endpoint where an invoices can be created.

1) Request to your service JSON:

JSON
// Invoice Create Request
{
    "invoiceCreationRequest": {
    "customerId": Optional<String>,
    "invoiceLines": [
      {
        "productId": string,
        "description" : string,
        "qty": int,
        "unitPrice": {
          "amount": double,
          "taxIncluded": boolean
        },
        "amount": double
      }
    ],
    "createDate": date
    "dueDate": date,
    "salesTermId": Optional<string>,
    "customerMessage": Optional<String>,
    "privateMessage": Optional<String>
  },
  "customerCreationRequest": Optional<{
    "name": string,
    "emailAddress": string,
    "companyName": Optional<String>,
    "billingAddress":{
      "lineOne": Optional<String>,
      "city": Optional<String>,
      "countrySubDivisionCode": Optional<String>,
      "postalCode": Optional<String>,
      "country": Optional<String>
    }
  }>,
  "accountId": string,
  "metadata": { 
    "requestId": string 
  }
}

Example JSON

JSON
// Example Request
{
  "invoiceCreationRequest": {
    "customerId": null,
    "invoiceLines": [
      {
        "productId": "PROD-3",
        "description": "Description to include in the invoice, overriding the product's default description",
        "qty": 3,
        "unitPrice": {
          "amount": 20.99,
          "taxIncluded": false
        },
        "amount": 4
      }
    ],
    "createDate": "2020-03-31T10:15:30Z",
    "dueDate": "2020-04-30T10:15:30Z",
    "salesTermId": "net-30",
    "customerMessage": "Message included on the invoice",
    "privateMessage": "Note attached to the invoice that only the accounting system user can see"
  },
  "customerCreationRequest": {
    "name": "Amy's Bird Sanctuary",
    "emailAddress": "Birds@birds.com",
    "companyName": null,
    "billingAddress": {
      "lineOne": null,
      "city": null,
      "countrySubDivisionCode": null,
      "postalCode": null,
      "country": null
    }
  },
  "metadata": {
    "requestId": "test-req-id"
  },
  "accountId": "123146316464684"
}

2) Response to HubSpot:

    200 (no body)

3) Request to HubSpot callback endpoint (/callback/invoice-create/{requestId}) JSON:

JSON
// Invoice Create Response
{
  "@result": "OK",
  "id": string
}

4) Response to your service JSON:

    200 or 400 with error info