> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.mercoa.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.mercoa.com/_mcp/server.

GL (General Ledger) accounts can be used to categorize line items on invoices for accounting purposes. Mercoa provides functionality to manage GL accounts and optionally use AI to predict appropriate GL accounts for invoice line items.

## Setting Up GL Accounts

GL accounts are stored in entity metadata. To add or update GL accounts for an entity, update the entity's `glAccountId` metadata key with an array of GL account objects:

Plain string values:

### Request

POST [https://api.mercoa.com/entity/\{entityId}/metadata/\{key}](https://api.mercoa.com/entity/\{entityId}/metadata/\{key})

**`GLAccounts`**

```curl GLAccounts
curl -X POST https://api.mercoa.com/entity/ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced/metadata/glAccountId \
     -H "Authorization: Bearer <token>" \
     -H "Content-Type: application/json" \
     -d '[
  "{key: '\''60205'\'', value: '\''60205 Marketing Expense'\''}",
  "{key: '\''60215'\'', value: '\''60215 Office Expense'\''}",
  "{key: '\''60225'\'', value: '\''60225 Payroll Expense'\''}",
  "{key: '\''60550'\'', value: '\''60550 Rent Expense'\''}"
]'
```

**`GLAccounts`**

```python GLAccounts
import requests

url = "https://api.mercoa.com/entity/ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced/metadata/glAccountId"

payload = ["{key: '60205', value: '60205 Marketing Expense'}", "{key: '60215', value: '60215 Office Expense'}", "{key: '60225', value: '60225 Payroll Expense'}", "{key: '60550', value: '60550 Rent Expense'}"]
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

**`GLAccounts`**

```typescript GLAccounts
import { MercoaClient } from "@mercoa/javascript";

const client = new MercoaClient({ token: "YOUR_TOKEN" });
await client.entity.metadata.update("ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced", "glAccountId", ["{key: '60205', value: '60205 Marketing Expense'}", "{key: '60215', value: '60215 Office Expense'}", "{key: '60225', value: '60225 Payroll Expense'}", "{key: '60550', value: '60550 Rent Expense'}"]);

```

**`GLAccounts`**

```go GLAccounts
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.mercoa.com/entity/ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced/metadata/glAccountId"

	payload := strings.NewReader("[\n  \"{key: '60205', value: '60205 Marketing Expense'}\",\n  \"{key: '60215', value: '60215 Office Expense'}\",\n  \"{key: '60225', value: '60225 Payroll Expense'}\",\n  \"{key: '60550', value: '60550 Rent Expense'}\"\n]")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

**`GLAccounts`**

```ruby GLAccounts
require 'uri'
require 'net/http'

url = URI("https://api.mercoa.com/entity/ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced/metadata/glAccountId")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "[\n  \"{key: '60205', value: '60205 Marketing Expense'}\",\n  \"{key: '60215', value: '60215 Office Expense'}\",\n  \"{key: '60225', value: '60225 Payroll Expense'}\",\n  \"{key: '60550', value: '60550 Rent Expense'}\"\n]"

response = http.request(request)
puts response.read_body
```

**`GLAccounts`**

```java GLAccounts
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.mercoa.com/entity/ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced/metadata/glAccountId")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("[\n  \"{key: '60205', value: '60205 Marketing Expense'}\",\n  \"{key: '60215', value: '60215 Office Expense'}\",\n  \"{key: '60225', value: '60225 Payroll Expense'}\",\n  \"{key: '60550', value: '60550 Rent Expense'}\"\n]")
  .asString();
```

**`GLAccounts`**

```php GLAccounts
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.mercoa.com/entity/ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced/metadata/glAccountId', [
  'body' => '[
  "{key: \'60205\', value: \'60205 Marketing Expense\'}",
  "{key: \'60215\', value: \'60215 Office Expense\'}",
  "{key: \'60225\', value: \'60225 Payroll Expense\'}",
  "{key: \'60550\', value: \'60550 Rent Expense\'}"
]',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

**`GLAccounts`**

```csharp GLAccounts
using RestSharp;

var client = new RestClient("https://api.mercoa.com/entity/ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced/metadata/glAccountId");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "[\n  \"{key: '60205', value: '60205 Marketing Expense'}\",\n  \"{key: '60215', value: '60215 Office Expense'}\",\n  \"{key: '60225', value: '60225 Payroll Expense'}\",\n  \"{key: '60550', value: '60550 Rent Expense'}\"\n]", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

**`GLAccounts`**

```swift GLAccounts
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = ["{key: '60205', value: '60205 Marketing Expense'}", "{key: '60215', value: '60215 Office Expense'}", "{key: '60225', value: '60225 Payroll Expense'}", "{key: '60550', value: '60550 Rent Expense'}"] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.mercoa.com/entity/ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced/metadata/glAccountId")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

JSON values with subtitles:

### Request

POST [https://api.mercoa.com/entity/\{entityId}/metadata/\{key}](https://api.mercoa.com/entity/\{entityId}/metadata/\{key})

**`GLAccountsWithSubtitles`**

```curl GLAccountsWithSubtitles
curl -X POST https://api.mercoa.com/entity/ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced/metadata/glAccountId \
     -H "Authorization: Bearer <token>" \
     -H "Content-Type: application/json" \
     -d '[
  "{key: '\''60205'\'', value: {value: '\''60205 Marketing Expense'\'', subtitle: '\''Expense'\''}}",
  "{key: '\''60215'\'', value: {value: '\''60215 Office Expense'\'', subtitle: '\''Expense'\''}}",
  "{key: '\''60225'\'', value: {value: '\''60225 Payroll Expense'\'', subtitle: '\''Expense'\''}}",
  "{key: '\''60550'\'', value: {value: '\''60550 Rent Expense'\'', subtitle: '\''Expense'\''}}"
]'
```

**`GLAccountsWithSubtitles`**

```python GLAccountsWithSubtitles
import requests

url = "https://api.mercoa.com/entity/ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced/metadata/glAccountId"

payload = ["{key: '60205', value: {value: '60205 Marketing Expense', subtitle: 'Expense'}}", "{key: '60215', value: {value: '60215 Office Expense', subtitle: 'Expense'}}", "{key: '60225', value: {value: '60225 Payroll Expense', subtitle: 'Expense'}}", "{key: '60550', value: {value: '60550 Rent Expense', subtitle: 'Expense'}}"]
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

**`GLAccountsWithSubtitles`**

```typescript GLAccountsWithSubtitles
import { MercoaClient } from "@mercoa/javascript";

const client = new MercoaClient({ token: "YOUR_TOKEN" });
await client.entity.metadata.update("ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced", "glAccountId", ["{key: '60205', value: {value: '60205 Marketing Expense', subtitle: 'Expense'}}", "{key: '60215', value: {value: '60215 Office Expense', subtitle: 'Expense'}}", "{key: '60225', value: {value: '60225 Payroll Expense', subtitle: 'Expense'}}", "{key: '60550', value: {value: '60550 Rent Expense', subtitle: 'Expense'}}"]);

```

**`GLAccountsWithSubtitles`**

```go GLAccountsWithSubtitles
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.mercoa.com/entity/ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced/metadata/glAccountId"

	payload := strings.NewReader("[\n  \"{key: '60205', value: {value: '60205 Marketing Expense', subtitle: 'Expense'}}\",\n  \"{key: '60215', value: {value: '60215 Office Expense', subtitle: 'Expense'}}\",\n  \"{key: '60225', value: {value: '60225 Payroll Expense', subtitle: 'Expense'}}\",\n  \"{key: '60550', value: {value: '60550 Rent Expense', subtitle: 'Expense'}}\"\n]")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

**`GLAccountsWithSubtitles`**

```ruby GLAccountsWithSubtitles
require 'uri'
require 'net/http'

url = URI("https://api.mercoa.com/entity/ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced/metadata/glAccountId")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "[\n  \"{key: '60205', value: {value: '60205 Marketing Expense', subtitle: 'Expense'}}\",\n  \"{key: '60215', value: {value: '60215 Office Expense', subtitle: 'Expense'}}\",\n  \"{key: '60225', value: {value: '60225 Payroll Expense', subtitle: 'Expense'}}\",\n  \"{key: '60550', value: {value: '60550 Rent Expense', subtitle: 'Expense'}}\"\n]"

response = http.request(request)
puts response.read_body
```

**`GLAccountsWithSubtitles`**

```java GLAccountsWithSubtitles
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.mercoa.com/entity/ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced/metadata/glAccountId")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("[\n  \"{key: '60205', value: {value: '60205 Marketing Expense', subtitle: 'Expense'}}\",\n  \"{key: '60215', value: {value: '60215 Office Expense', subtitle: 'Expense'}}\",\n  \"{key: '60225', value: {value: '60225 Payroll Expense', subtitle: 'Expense'}}\",\n  \"{key: '60550', value: {value: '60550 Rent Expense', subtitle: 'Expense'}}\"\n]")
  .asString();
```

**`GLAccountsWithSubtitles`**

```php GLAccountsWithSubtitles
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.mercoa.com/entity/ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced/metadata/glAccountId', [
  'body' => '[
  "{key: \'60205\', value: {value: \'60205 Marketing Expense\', subtitle: \'Expense\'}}",
  "{key: \'60215\', value: {value: \'60215 Office Expense\', subtitle: \'Expense\'}}",
  "{key: \'60225\', value: {value: \'60225 Payroll Expense\', subtitle: \'Expense\'}}",
  "{key: \'60550\', value: {value: \'60550 Rent Expense\', subtitle: \'Expense\'}}"
]',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

**`GLAccountsWithSubtitles`**

```csharp GLAccountsWithSubtitles
using RestSharp;

var client = new RestClient("https://api.mercoa.com/entity/ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced/metadata/glAccountId");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "[\n  \"{key: '60205', value: {value: '60205 Marketing Expense', subtitle: 'Expense'}}\",\n  \"{key: '60215', value: {value: '60215 Office Expense', subtitle: 'Expense'}}\",\n  \"{key: '60225', value: {value: '60225 Payroll Expense', subtitle: 'Expense'}}\",\n  \"{key: '60550', value: {value: '60550 Rent Expense', subtitle: 'Expense'}}\"\n]", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

**`GLAccountsWithSubtitles`**

```swift GLAccountsWithSubtitles
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = ["{key: '60205', value: {value: '60205 Marketing Expense', subtitle: 'Expense'}}", "{key: '60215', value: {value: '60215 Office Expense', subtitle: 'Expense'}}", "{key: '60225', value: {value: '60225 Payroll Expense', subtitle: 'Expense'}}", "{key: '60550', value: {value: '60550 Rent Expense', subtitle: 'Expense'}}"] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.mercoa.com/entity/ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced/metadata/glAccountId")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

GL Accounts can also be automatically synced using [Accounting Sync](/accounts-payable/accounting-sync).

## Using GL Accounts

If you use Mercoa's React Component Library, line items show a dropdown of GL accounts for the entity.

When selected, the `glAccountId` is added to the line item as a special `glAccountId` field in the `lineItem` object. It's not added to the `lineItem.metadata` object.

This `glAccountId` field can be used to [filter invoices](/api-reference/entity/invoice/find#request.query.lineItemGlAccountId) by GL account.

## Using AI to Predict GL Accounts

Mercoa can use AI to predict GL accounts for line items.

To enable this:

1. Make sure the entity has a `glAccountId` metadata key set with the list of GL accounts provided in the previous section.
2. Make sure the [predictMetadata](/api-reference/entity/customization/update#request.body.ocr.predictMetadata) is set to true for the entity (defaults to true).
3. Make sure all [lineItem ocr fields](/api-reference/entity/customization/update#request.body.ocr) are set to true (defaults to true).

Mercoa needs the user to manually tag the GL accounts for the first invoice. Once the initial invoice is created and manually tagged with GL accounts, the AI can predict line item GL accounts for new invoices from the same vendor.