Skip to main content
Every record on the API carries a metadata object: a set of key/value pairs — strings, numbers or booleans — that belong to you. PracticeHub never reads or displays them; they exist so an integration can tag records with its own ids (a CRM contact, an order number, a sync cursor) and find them again without keeping a mapping table.

Writing metadata

Include metadata in the body of any create or update on a writable resource. Keys are merged: keys you send are set, keys you omit are left alone, and a null value removes a key.
Metadata is shared across every integration on the account (there is one metadata object per record, not one per key), so prefix keys with your app name if several integrations may touch the same records. Metadata is removed with its record.

Filtering by metadata

Any resource can be filtered on any metadata key with metadata[key]=operator:value, using the same operators as ordinary attributes:
metadata[key]=null matches records that do not have the key — useful for “everything I have not synced yet”. Comparisons are typed: when the operand is a number, gt/gte/lt/lte/between compare numerically against values you stored as numbers (metadata[score]=gt:9 matches 10, not the string "10"); with any other operand they compare as text, so ISO dates (2026-09-01) and times sort correctly. eq/in match on the value’s canonical text (10, true, hs-778), whatever its type. contains is a case-insensitive substring match with nothing to escape:
Equality, in and prefix like filters use an index and stay fast at any size; contains and leading-wildcard like scan the key’s values for the account.
With curl, pass -g (or URL-encode [ and ]) so the shell does not expand the brackets.