Tags

Tags are flexible metadata elements that can be associated with voucher statements, allowing for additional categorization and filtering of financial data.

Endpoints

List Tags

GET /api/v2/tags

Retrieves a paginated list of tags.

Query Parameters

Parameter Type Required Description
client_account_id integer No Filter tags by client account. When omitted, the list is scoped to every client account you can access; an account you cannot access returns 403 tag.access_denied
name string No Filter tags by name (partial match)
is_active boolean No Filter by active status (default: true). Pass null to include all
page integer No Page number (default: 1)
per_page integer No Items per page (default: 100)
with string No Include related resources in the response (supported: statistics)

Response

{
  "data": [
    {
      "id": 123,
      "name": "Travel Expenses",
      "client_account_id": 456,
      "sequence_number": 1,
      "is_active": true,
      "created_at": "2024-04-15T10:00:00Z",
      "updated_at": "2024-04-15T10:00:00Z",
      "created_by_id": 789,
      "updated_by_id": 789
    }
  ],
  "meta": {
    "page": 1,
    "pages": 1,
    "per_page": 100,
    "records": 1
  }
}

Get Tag

GET /api/v2/tags/{id}

Retrieves a specific tag by ID.

Query Parameters

Parameter Type Required Description
with string No Include related resources in the response (supported: statistics)

Response

{
  "id": 123,
  "name": "Travel Expenses",
  "client_account_id": 456,
  "sequence_number": 1,
  "is_active": true,
  "created_at": "2024-04-15T10:00:00Z",
  "updated_at": "2024-04-15T10:00:00Z",
  "created_by_id": 789,
  "updated_by_id": 789
}

Create Tag

POST /api/v2/tags

Creates a new tag.

Request Body

Field Type Required Description
name string Yes The name of the tag
client_account_id integer Yes The ID of the client account
is_active boolean No Defaults to true

Example Request

{
  "name": "Travel Expenses",
  "client_account_id": 456
}

Response

{
  "id": 123,
  "name": "Travel Expenses",
  "client_account_id": 456,
  "sequence_number": 1,
  "is_active": true,
  "created_at": "2024-04-15T10:00:00Z",
  "updated_at": "2024-04-15T10:00:00Z",
  "created_by_id": 789,
  "updated_by_id": 789
}

Update Tag

PUT|POST /api/v2/tags/{id}

Updates an existing tag. Only the fields present in the body are applied, so name and is_active can be sent on their own.

client_account_id may be sent, but only with the tag’s current value — changing it is rejected with tag.client_account_immutable.

Request Body

Field Type Required Description
name string No The new name for the tag
is_active boolean No Set to false to deactivate the tag (same effect as DELETE, subject to the same balance check)

Example Request

{
  "name": "International Travel"
}

Response

{
  "id": 123,
  "name": "International Travel",
  "client_account_id": 456,
  "sequence_number": 1,
  "is_active": true,
  "created_at": "2024-04-15T10:00:00Z",
  "updated_at": "2024-04-15T15:30:00Z",
  "created_by_id": 789,
  "updated_by_id": 789
}

Deactivate Tag

DELETE /api/v2/tags/{id}

Deactivates a tag by setting its is_active status to false. The tag record is preserved for historical purposes.

Response

{
  "id": 123,
  "name": "Travel Expenses",
  "client_account_id": 456,
  "sequence_number": 1,
  "is_active": false,
  "created_at": "2024-04-15T10:00:00Z",
  "updated_at": "2024-04-15T16:00:00Z",
  "created_by_id": 789,
  "updated_by_id": 789
}

Deactivation Validation

When attempting to deactivate a tag, the system performs validation to ensure data integrity:

  • Balance Checking: The system checks if any accounting accounts with mandatory tag dimensions have non-zero balances for this specific tag.
  • Validation Failure: If any accounts have non-zero balances, the deactivation is denied with a 400 Bad Request error.
  • Error Details: The error message includes specific account codes and their balances to help identify which transactions need to be resolved.
Example Error Response
{
    "error": {
        "code": "common.validation_error",
        "message": "Cannot deactivate tag: account 1500: 3200.00, account 2400: -800.00",
        "request_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab"
    }
}

This validation ensures that tags cannot be deactivated while they still have outstanding balances, maintaining the integrity of your accounting records.

Relationships

Relationship Type Description
statistics object Aggregated balances for the tag, broken down by accounting account code

Statistics are limited to balance-sheet accounts (account code 2999 and below). Balances for income-statement accounts (account code 3000 and above) are not included, and accounts whose balance for the tag is zero are left out of balances entirely.

Example Response with Statistics

GET /api/v2/tags/123?with=statistics
{
  "id": 123,
  "name": "Travel Expenses",
  "client_account_id": 456,
  "sequence_number": 1,
  "is_active": true,
  "created_at": "2024-04-15T10:00:00Z",
  "updated_at": "2024-04-15T10:00:00Z",
  "created_by_id": 789,
  "updated_by_id": 789,
  "statistics": {
    "balances": [
      { "account_code": "1500", "balance": "3200.00" },
      { "account_code": "2400", "balance": "-800.00" }
    ]
  }
}

Voucher Statement Integration

Tags can be associated with voucher statements, allowing for multiple tags per voucher.

Example Voucher Statement with Tags

{
  "id": 456,
  "voucher_id": 789,
  "client_account_id": 456,
  "tags": [
    {
      "id": 123,
      "name": "Travel Expenses",
      "sequence_number": 1,
      "client_account_id": 456
    },
    {
      "id": 124,
      "name": "Marketing",
      "sequence_number": 2,
      "client_account_id": 456
    }
  ],
  "purpose": "Business trip to client meeting",
  "additional_information": "Annual strategic planning session"
}

Error Responses

Errors use the standard v2 envelope ({"error": {"code", "message", "request_id"}}) — see Error Handling.

Status Code Description
400 tag.missing_request_body POST /tags was sent without a body
400 tag.invalid_request_body The body is not a JSON object
400 common.serialization_error The body could not be deserialized into a tag
400 tag.client_account_immutable The body’s client_account_id differs from the tag’s
400 common.validation_error A validation rule failed: no client_account_id, an inactive client account, a missing name, a duplicate name on create, or a balance blocking deactivation
403 tag.access_denied No access to the client account or tag
404 tag.not_found Tag not found

Business Rules

  1. Tags are associated with a specific client account
  2. Users must have access to the client account to manage its tags
  3. The client_account_id cannot be changed after tag creation
  4. Each tag is automatically assigned a unique sequence number within its client account
  5. Tags can be associated with multiple voucher statements (many-to-many relationship)
  6. Tag names must be unique within a client account; the check runs when a tag is created, not when one is renamed
  7. Creation and update timestamps and user IDs are automatically tracked

Common Use Cases

  1. Categorizing expenses by purpose or project
  2. Adding supplementary search criteria to vouchers
  3. Grouping related vouchers for reporting
  4. Creating custom dimensions for financial analysis

Best Practices

  1. Use concise, descriptive tag names
  2. Maintain consistent naming conventions
  3. Avoid creating too many similar tags
  4. Use tags as an additional dimension rather than replacing existing categorization systems
  5. Consider creating a tagging strategy for consistency across the organization