# 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](/guides/authentication.md). 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.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://developer.laurel.ai/guides/building-a-connector.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
