Building A Connector

Overview

When there isn't a connector available for your specific billing system, Laurel APIs allow you to build your own. This guide will walk you through the process of building a connector.

Prerequisites

Laurel APIs use OAuth 2.0 for authentication. You will need to contact our support team to create an OAuth 2.0 client. Additionally you will need to know your customerId. You will need the following:

  • Your customerId

  • Your application clientId

  • Your application clientSecret

Ingress

Client Data

POST /api/v1/customers/{customerId}/clients/import

The first step in building a connector is defining how client data is formatted.

This is the required data for a client:

{
  "externalId": "string",
  "name": "string",
  "callSign": "string",
  "description": "string"
}
  • externalId is a unique identifier for the client in your system. This can't be modified in the future. This is also provided in the exported time entry.

  • name is the name of the client.

  • callSign is a searchable tag for the client in Laurel. Generally this is the client code in legal billing systems.

  • description is a description of the client.

Initiative Data

POST /api/v1/customers/{customerId}/initiatives/import

The next step is defining how initiative data is formatted. Note these are generally considered "Matters" in legal billing systems or "Projects" in accounting billing systems.

This is the required data for a initiative:

{
  "billingType": "billable",
  "externalId": "string",
  "name": "string",
  "description": "string",
  "callSign": "string",
  "clientExternalId": "string",
  "unitIncrements": number,
  "status": "active"
}
  • billingType is the type of billing for the initiative. This can be billable or non-billable and is case-sensitive. Generally all accountable/pro-bono etc. initiatives are considered non-billable for display purposes.

  • externalId is a unique identifier for the initiative in your system. This can't be modified in the future. This is also provided in the exported time entry.

  • name is the name of the initiative.

  • description is a description of the initiative.

  • callSign is a searchable tag for the initiative in Laurel. Generally this is the initiative code in legal billing systems.

  • clientExternalId is the unique identifier of the client that the initiative is associated with.

  • unitIncrements is the smallest unit of time that can be billed for the initiative. This is in seconds. ex. if an initiative can be billed in 0.1 increments, set the value to 360.

  • status is the status of the initiative. This can be active or inactive and is case-sensitive. When the status is inactive, the initiative is no longer searchable within Laurel.

Code Type Data

POST /api/v1/customers/{customerId}/code-types/import

The next step is defining how code type data is formatted. Most firms make use of a code type system to categorize time entries. Generally legal firms have some concept of a task code and/or activity code. Accounting firms may use project codes, task codes, out of scope codes etc.

This is the required data for a code type:

{
  "externalId": "string",
  "name": "string",
  "semanticType": "action",
  "customerDefaultable": boolean,
  "userDefaultable": boolean
}
  • externalId is a unique identifier for the code type in your system. This can't be modified in the future. Generally this is set to task-code or something similar.

  • name is the name of the code type. This is displayed to the user without - characters. ex. task-code would be displayed as Task Code.

  • semanticType is the semantic type of the code type. This is used to categorize the code type. Here are a list of semantic code types that Laurel supports (otherwise, set the value to null):

    • 'action'

    • 'activity'

    • 'location'

    • 'phase'

    • 'task'

  • customerDefaultable is a boolean value that determines if the code type is defaultable for customers. If true, the code type will be available to default to a specific code for the entire firm. If false, the code type will not be available to default to a specific code for the entire firm.

  • userDefaultable is a boolean value that determines if the code type is defaultable for users. If true, the code type will be available to default to a specific code for the user. If false, the code type will not be available to default to a specific code for the user.

Code Data

POST /api/v1/customers/{customerId}/codes/import

The next step is defining how code data is formatted. These are the actual phase/task/activity/project/action etc. codes that are used to categorize time entries.

This is the required data for a code:

{
  "externalId": "string",
  "name": "string",
  "description": "string",
  "codeTypeExternalId": "string"
}
  • externalId is a unique identifier for the code in your system. This can't be modified in the future. This is also provided in the exported time entry.

  • name is the name of the code. (ex. L110)

  • description is a description of the code. (ex. Research)

  • codeTypeExternalId is the unique identifier of the code type that the code is associated with. (ex. task-code)

Code Range Data

POST /api/v1/customers/{customerId}/initiatives/{initiativeExternalId}/codes

If only certain codes can be selected for certain initiatives, you can define code ranges. This is optional, but usually present in many systems.

This is the required data for a code range:

{
  "codeExternalIds": [
    "string"
  ]
}
  • codeExternalIds is an array of unique identifiers (code externalId) of the codes that are associated with the initiative.

Also note the addition of the initiativeExternalId in the path. This is the unique identifier of the initiative (initiative externalId) that the code range is associated with.

Egress

Get Pending Time Entry Data

Once a user decides their entires are ready to be released, they are marked as "pending" in our system and are locked from being edited. This lets us know those entries are ready to be written to the billing system.

GET /api/v2/customers/{customerId}/entries/export

This returns a list of entires that are ready to be released in this format:

[
  {
    "_id": "string",
    "codes": [
      {
        "code": {
            "_id": "string",
            "externalId": "string",
            "name": "string",
            "description": "string",
            "type": {
                "_id": "string",
                "externalId": "string",
                "name": "string",
                "semanticType": "action"
            }
        },
        "assignedBy": AssignBy, // (enum 'user' or 'laurel')
      }
    ],
    "createdAt": "2022-08-12T00:00:00.000Z",
    "customerId": "string",
    "externalId": "string",
    "incrementDurationInSeconds": 0,
    "initiative": {
        client: {
          "_id": "string",
          "externalId": "string",
          "name": "string",
          "description": "string",
          "callSign": "string"
        },
        externalId: "string",
        name: "string",
    },
    "summary": "string",
    "unitIncrementCount": 0,
    "updatedAt": "2022-08-12T00:00:00.000Z",
    "userId": "string",
    "workDate": "2022-08-12"
  }
]
  • _id is the unique identifier of the time entry in Laurel.

  • codes is an array of codes that are associated with the time entry. This includes the code externalId for import into your billing system.

  • createdAt is the date and time the time entry was created in Laurel.

  • customerId is the unique identifier of the customer that the time entry is associated with. This will be your customerId.

  • externalId is the unique identifier of the time entry in your billing system. This will update the time entry in Laurel with the externalId so that it can be cross-referenced in the future.

  • incrementDurationInSeconds is the duration of the time entry in seconds. This is the actual time worked and should be used for billing.

  • initiative is the initiative that the time entry is associated with. This includes the initiative externalId and the client externalId for import into your billing system.

  • summary is the description of the time entry.

  • unitIncrementCount is the number of units of time worked. This is the number of billable increments an entry is billed for. Generally this value isn't used in an export as it requires calculation.

  • updatedAt is the date and time the time entry was last updated in Laurel. When the time entry is in the pending state, this is the date and time the time entry was marked as pending.

  • userId is the unique identifier of the user in Laurel that the time entry is associated with.

    • If you need to find more information about the user, you can use the GET /api/v1/customers/{customerId}/users/{userId} endpoint.

  • workDate is the date the time entry was worked on (also known as transaction date).

Additionally, two URL parameters are required:

  • releasedAfter an ISO 8601 date string to filter time entries that were released after this date and time.

  • releasedOnOrBefore an ISO 8601 date string to filter time entries that were released on or before this date and time.

Alternate Get Pending Time Data

Generally the above endpoint is used to get all pending time entries. However, if you you require more details on the time entry itself, this endpoint can be used.

GET /api/v1/customers/{customerId}/entries/release-pending

This returns a list of entries that are ready to be released in this format:

[
  {
    "_id": "string",
    "customerId": "string",
    "userId": "string",
    "workDate": "2022-08-12",
    "summary": "string",
    "unitIncrementCount": 0,
    "incrementDurationInSeconds": 0,
    "initiativeProps": {
      "type": "pms",
      "colorHex": "fec828",
      "tags": [
        "pinned"
      ],
      "nickname": "string",
      "initiative": {
        "type": "pms",
        "_id": "string",
        "billingType": "billable",
        "callSign": "string",
        "unitIncrements": 0,
        "externalId": "string",
        "name": "string",
        "description": "string",
        "client": {
          "_id": "string",
          "externalId": "string",
          "name": "string",
          "description": "string",
          "callSign": "string"
        }
      }
    },
    "externalId": "string",
    "codes": [
      {
        "_id": "string",
        "externalId": "string",
        "name": "string",
        "description": "string",
        "type": {
          "_id": "string",
          "externalId": "string",
          "name": "string",
          "semanticType": "action"
        }
      }
    ]
  }
]
  • _id is the unique identifier of the time entry in Laurel.

  • customerId is the unique identifier of the customer that the time entry is associated with. This will be your customerId.

  • userId is the unique identifier of the user in Laurel that the time entry is associated with.

    • If you need to find more information about the user, you can use the GET /api/v1/customers/{customerId}/users/{userId} endpoint.

  • workDate is the date the time entry was worked on (also known as transaction date).

  • summary is the description of the time entry.

  • unitIncrementCount is the number of units of time worked. This is the number of billable increments an entry is billed for. Generally this value isn't used in an export as it requires calculation.

  • incrementDurationInSeconds is the duration of the time entry in seconds. This is the actual time worked and should be used for billing.

  • initiativeProps is the initiative that the time entry is associated with. This includes the initiative externalId and the client externalId for import into your billing system.

  • codes is an array of codes that are associated with the time entry. This includes the code externalId for import into your billing system.

Mark Time Entry Data as Successfully Released

Once you have successfully written the time entry to your billing system, you can mark the time entry as successfully released in Laurel.

POST /api/v1/customers/{customerId}/users/{userId}/entries/{entryId}/release-succeeded

{
  "externalId": "string"
}
  • externalId is the unique identifier of the time entry in your billing system. This will update the time entry in Laurel with the externalId so that it can be cross-referenced in the future.

Mark Time Entry Data as Failed to Release

Once you have attempted to write the time entry to your billing system and it has failed, you can mark the time entry as failed to release in Laurel.

POST /api/v1/customers/{customerId}/users/{userId}/entries/{entryId}/release-failed

{
  "errors": [
    "string"
  ]
}
  • errors is an array of strings that describe the errors that occurred when attempting to write the time entry to your billing system. This will update the time entry in Laurel with the errors so that it can be displayed to the user. Ex. they may have entered time for an initiative that has since been closed in your billing system.

Last updated