unofficial_capacities

An unofficial Dart client for the Capacities REST API, built on dio.

It wraps all 15 operations across the Space, Object, Search, and Blocks endpoints in a single CapacitiesClient, with typed DTOs, Bearer auth, X-Capacities-Api-Version header handling, and typed error mapping.

Features

  • Full endpoint coveragegetSpace, getSpaceStructures, getObject, createObject, updateObject, deleteObject, saveWeblink, getObjectMarkdown, createObjectMarkdown, updateObjectMarkdown, searchObjects, appendBlock, appendDailyNoteBlock, updateBlock, deleteBlock.
  • Typed modelsSpace, Structure, ApiObject, ObjectMarkdown, SearchResult.
  • Sealed block & token unionsBlock (TextBlock, CodeBlock, GridBlock, GroupBlock, MathBlock, EntityBlock, HorizontalLineBlock, UnsupportedBlock) and Token (TextToken, LinkToken, MathToken, CodeToken, UnsupportedToken). Unknown types round-trip losslessly through the Unsupported* fallbacks.
  • Convenience helpersProperties and Tokens builders for the API's discriminated-union value shapes, ApiObjectBlocks accessors, and capacities:// deep-link parsing/building.
  • Typed errors — API failures surface as CapacitiesApiException instead of raw DioException.

Getting started

Add the dependency:

dependencies:
  unofficial_capacities: ^0.3.0

Then:

dart pub get

You'll need a Capacities API token from your account settings.

Usage

import 'package:unofficial_capacities/unofficial_capacities.dart';

Future<void> main() async {
  // Pass the token explicitly, or set CAPACITIES_API_TOKEN in the environment.
  final client = CapacitiesClient(apiToken: 'cap-api-...');

  // Inspect the space and its structures.
  final space = await client.getSpace();
  final structures = await client.getSpaceStructures();
  final structureId = structures.first.id;

  // Create an object with a title property.
  final object = await client.createObject(
    structureId: structureId,
    properties: {
      'title': Properties.title('Hello from Dart'),
    },
  );

  // Append blocks to it.
  await client.appendBlock(
    id: object.id,
    blocks: [
      TextBlock(tokens: [TextToken('A paragraph.')]),
      CodeBlock(text: 'print("hi");', lang: 'dart'),
    ],
    propertyId: 'markdownNotes',
  );

  // Search.
  final results = await client.searchObjects(query: 'Hello', limit: 10);
  print(results.map((r) => r.title));
}

Environment-based auth

If apiToken is omitted, the client reads CAPACITIES_API_TOKEN from the environment and throws an ArgumentError if neither is present:

final client = CapacitiesClient();

Parse and build capacities:// desktop app links:

final link = CapacitiesLink.parse('capacities://spaceId/objectId?bid=blockId');
print(link.objectId);

Error handling

try {
  await client.getObject(id: 'missing');
} on CapacitiesApiException catch (e) {
  print(e); // status code + message mapped from the API response
}

Testing

The automated suite is offline and deterministic — it mocks Dio with http_mock_adapter and never touches the network:

dart test

Live, manual verification scripts live in e2e_tests/ and hit the real API. Run them before a release; see e2e_tests/README.md.

Additional information

This is an unofficial client and is not affiliated with or endorsed by Capacities.