API reference

CE requirements API

Continuing education requirements for behavioral health licenses in the 50 US states and DC. Read-only JSON over HTTPS, with every version kept.

Base URL
https://api.verbena.health/v1
Version
v1
Specification
OpenAPI 3.1, JSON

Overview

The API returns continuing education requirements for behavioral health licenses in the 50 US states and DC: social work, counseling, psychology, marriage and family therapy, and behavior analysis. Each record is one license in one jurisdiction, with its hours per renewal cycle, cycle length, required topics, limits on self-study and live hours, the board's own notes, and links to where the rule is published.

Every version is kept. Ask what applies now, what applied on a date with as_of, or what changed since a date with /changes.

Informational only. The data is compiled from public licensing-board sources. It is not legal advice; verify current requirements with the relevant board.

Your first request
curl -s "https://api.verbena.health/v1/requirements/CA/Social%20Work" \
  -H "Authorization: Bearer $VERBENA_API_KEY"

Authentication

Send your key in the Authorization header on every request: Authorization: Bearer vb_.... A request without a valid key answers 401.

On the Individual plan, create keys on the Account page in the Verbena app. Partners receive a key from us; get in touch.

Keys are read-only. A key is shown once, when it is created, and only a hash is stored, so a lost key is replaced rather than recovered. A key can carry an expiry date, and it can be revoked at any time.

Call the API from your servers. It does not accept cross-origin requests from browsers, and a key does not belong in a web page.

Requests and responses

Every endpoint is a GET under https://api.verbena.health/v1 and answers JSON with a data field. Some responses add fields, such as next_cursor or summary.

  • Timestamps are ISO 8601 in UTC. Numbers are JSON numbers.
  • Filters that take several values accept a comma list or a repeated parameter: state=CA,NY or state=CA&state=NY. license is the exception: repeat it, because license labels can contain commas.
  • Jurisdiction codes and license groups are case-insensitive.
  • Verbena serves US jurisdictions only. A code outside the US is 404 unknown_jurisdiction.
  • Responses can gain fields over time. Ignore fields you do not recognize.

Errors

Errors are JSON with a stable error code to branch on, and usually a detail written for people. Do not parse detail.

StatusCodeMeaning
400bad_as_ofas_of is not a date.
400bad_sincesince is missing or not a date.
400bad_queryA query value contains a NUL character.
400bad_qq was given more than once.
400bad_coveredcovered is not true or false.
400unknown_regionA reference list was filtered by a region other than US.
400unknown_license_groupA reference list was filtered by a group that is not one of the five.
400unsupported_filterlicense or q was sent to /coverage.
401missing_api_keyNo Authorization header.
401invalid_api_keyThe key is unknown, revoked or expired.
403plan_requiredThe key's account plan does not include API access.
404unknown_jurisdictionThe code is not a jurisdiction Verbena serves.
404unknown_license_groupThe path names a group that is not one of the five.
404not_coveredNothing is on record for the jurisdiction and group, at the as_of date if given.

Pagination

/requirements returns up to limit records, 50 by default and 200 at most, with a next_cursor. Pass it back as cursor until it comes back null. The cursor is a position in a stable order, so a walk stays consistent even if data changes while you page. The reference lists are not paginated.

Caching

Every successful response carries a weak ETag. Send it back as If-None-Match; if nothing changed, the API answers 304 with no body. /meta reports when requirements last changed.

Keeping a copy current

Store records by jurisdiction code, license group and license together; that is a record's identity across versions. Then either pull your scope from /requirements on a schedule, or poll /changes with the time of your last run and apply each row. Doing both, polling changes daily and pulling in full weekly, keeps a copy from drifting.

Requirements

List requirements

GET/v1/requirements

Current requirements by default, one record per license, in a stable order. Pass as_of for the versions in force on a date instead. Filters combine. A filter that matches nothing returns an empty data array. A license_group value that is not one of the five is ignored.

Query parameters

ParameterTypeDescription
state
query
array of string Jurisdiction codes, case-insensitive. Repeat the parameter or use a comma list: state=CA,NY.
region
query
array of string: US Regions. US is the only region served; any other value matches nothing.
license_group
query
array of string: Social Work Counseling Psychology MFT BCBA License groups, case-insensitive. Repeat the parameter or use a comma list.
license
query
array of string An exact license label, matched case-insensitively. Repeat the parameter for several; labels can contain commas, so commas do not split.
confidence
query
string: high medium low unverified One confidence value.
cpd
query
boolean true for regimes with no fixed hours, false for the rest.
fully_async_ok
query
boolean true for requirements with no live-session minimum, false for those with one.
as_of
query
string An ISO 8601 date or date-time. Returns the versions in force at that moment instead of the current ones.
limit
query
integer
default 50
Page size, 1 to 200.
cursor
query
string The next_cursor from the previous page.

Responses

  • 200 A page of requirements. Follow next_cursor until it is null.
  • 304 Not modified: the If-None-Match ETag still matches. No body.
  • 400 A malformed date or query value. bad_as_of bad_query
  • 401 The key is missing, unknown, revoked or expired. missing_api_key invalid_api_key
  • 403 The key belongs to an account whose plan does not include API access. plan_required
Request
curl -s "https://api.verbena.health/v1/requirements?state=CA,NY&license_group=Social%20Work" \
  -H "Authorization: Bearer $VERBENA_API_KEY"
Response 200
{
  "data": [
    {
      "jurisdiction": {
        "code": "CA",
        "name": "California",
        "region": "US",
        "board": "Board of Behavioral Sciences"
      },
      "license_group": "Social Work",
      "license": "LCSW (Licensed Clinical Social Worker)",
      "cpd": false,
      "total_hours": 36,
      "cycle_years": 2,
      "live_interactive_required_hours": 0,
      "fully_async_ok": true,
      "home_study_cap": "The board's statement on self-study limits, as plain text.",
      "required_topics": [
        {
          "topic": "Law and Ethics",
          "hours": 6,
          "note": "Every renewal."
        }
      ],
      "board_nuances": "The board's own notes: exemptions, deadlines, anything that is not a number.",
      "source_urls": [
        "https://www.bbs.ca.gov/"
      ],
      "confidence": "medium",
      "verified_at": null,
      "effective_from": "2026-08-12T14:03:11.000Z",
      "effective_to": null,
      "is_current": true,
      "ingested_at": "2026-08-12T14:03:11.000Z"
    }
  ],
  "next_cursor": "Q0F8U29jaWFsIFdvcmt8TENTVw"
}

Get the requirements for a jurisdiction and license group

GET/v1/requirements/{state}/{license_group}

The records for one jurisdiction and license group, as an array, because a jurisdiction can hold more than one license in a group. Pass as_of for the versions in force on a date.

Path parameters

ParameterTypeDescription
state required
path
string A jurisdiction code, case-insensitive.
license_group required
path
string: Social Work Counseling Psychology MFT BCBA A license group, case-insensitive.

Query parameters

ParameterTypeDescription
as_of
query
string An ISO 8601 date or date-time. Returns the versions in force at that moment instead of the current ones.

Responses

  • 200 One record per license in the group.
  • 304 Not modified: the If-None-Match ETag still matches. No body.
  • 400 A malformed as_of date. bad_as_of
  • 401 The key is missing, unknown, revoked or expired. missing_api_key invalid_api_key
  • 403 The key belongs to an account whose plan does not include API access. plan_required
  • 404 The jurisdiction is not one Verbena serves, the group is not one of the five, or nothing is on record for the pair (at the as_of date, if given). unknown_jurisdiction unknown_license_group not_covered
Request
curl -s "https://api.verbena.health/v1/requirements/CA/Social%20Work" \
  -H "Authorization: Bearer $VERBENA_API_KEY"
Response 200
{
  "data": [
    {
      "jurisdiction": {
        "code": "CA",
        "name": "California",
        "region": "US",
        "board": "Board of Behavioral Sciences"
      },
      "license_group": "Social Work",
      "license": "LCSW (Licensed Clinical Social Worker)",
      "cpd": false,
      "total_hours": 36,
      "cycle_years": 2,
      "live_interactive_required_hours": 0,
      "fully_async_ok": true,
      "home_study_cap": "The board's statement on self-study limits, as plain text.",
      "required_topics": [
        {
          "topic": "Law and Ethics",
          "hours": 6,
          "note": "Every renewal."
        }
      ],
      "board_nuances": "The board's own notes: exemptions, deadlines, anything that is not a number.",
      "source_urls": [
        "https://www.bbs.ca.gov/"
      ],
      "confidence": "medium",
      "verified_at": null,
      "effective_from": "2026-08-12T14:03:11.000Z",
      "effective_to": null,
      "is_current": true,
      "ingested_at": "2026-08-12T14:03:11.000Z"
    }
  ]
}

Get every version for a jurisdiction and license group

GET/v1/requirements/{state}/{license_group}/history

Every version on record, current and closed, newest first within each license. effective_from and effective_to give each version its window.

Path parameters

ParameterTypeDescription
state required
path
string A jurisdiction code, case-insensitive.
license_group required
path
string: Social Work Counseling Psychology MFT BCBA A license group, case-insensitive.

Query parameters

No parameters.

Responses

  • 200 All versions, possibly an empty array.
  • 304 Not modified: the If-None-Match ETag still matches. No body.
  • 401 The key is missing, unknown, revoked or expired. missing_api_key invalid_api_key
  • 403 The key belongs to an account whose plan does not include API access. plan_required
  • 404 The jurisdiction is not one Verbena serves, or the group is not one of the five. unknown_jurisdiction unknown_license_group
Request
curl -s "https://api.verbena.health/v1/requirements/CA/Social%20Work/history" \
  -H "Authorization: Bearer $VERBENA_API_KEY"
Response 200
{
  "data": [
    {
      "jurisdiction": {
        "code": "CA",
        "name": "California",
        "region": "US",
        "board": "Board of Behavioral Sciences"
      },
      "license_group": "Social Work",
      "license": "LCSW (Licensed Clinical Social Worker)",
      "cpd": false,
      "total_hours": 36,
      "cycle_years": 2,
      "live_interactive_required_hours": 0,
      "fully_async_ok": true,
      "home_study_cap": "The board's statement on self-study limits, as plain text.",
      "required_topics": [
        {
          "topic": "Law and Ethics",
          "hours": 6,
          "note": "Every renewal."
        }
      ],
      "board_nuances": "The board's own notes: exemptions, deadlines, anything that is not a number.",
      "source_urls": [
        "https://www.bbs.ca.gov/"
      ],
      "confidence": "medium",
      "verified_at": null,
      "effective_from": "2026-08-12T14:03:11.000Z",
      "effective_to": null,
      "is_current": true,
      "ingested_at": "2026-08-12T14:03:11.000Z"
    }
  ]
}

List changes since a date

GET/v1/changes

One row per version that took effect, or was closed, on or after since, newest first. added has no predecessor, amended carries a per-field diff, and retired is a version closed with no successor. Each row carries the full current record, so no second call is needed.

By default only material rows come back: a rule field or the board notes moved, or a requirement was added or retired. include=all also returns changes to our own metadata: confidence, the verification date and the source list. Overlapping windows are safe; identify a row by its jurisdiction, license group, license and event_at.

Query parameters

ParameterTypeDescription
since required
query
string An ISO 8601 date or date-time. Inclusive.
state
query
array of string Jurisdiction codes, case-insensitive. Repeat the parameter or use a comma list: state=CA,NY.
region
query
array of string: US Regions. US is the only region served; any other value matches nothing.
license_group
query
array of string: Social Work Counseling Psychology MFT BCBA License groups, case-insensitive. Repeat the parameter or use a comma list.
include
query
string: all all adds changes to our own metadata; the default returns material changes only.

Responses

  • 200 Change rows, with the window and mode that answered.
  • 304 Not modified: the If-None-Match ETag still matches. No body.
  • 400 since is missing or not a date. bad_since
  • 401 The key is missing, unknown, revoked or expired. missing_api_key invalid_api_key
  • 403 The key belongs to an account whose plan does not include API access. plan_required
Request
curl -s "https://api.verbena.health/v1/changes?since=2026-09-01&state=CA" \
  -H "Authorization: Bearer $VERBENA_API_KEY"
Response 200
{
  "data": [
    {
      "jurisdiction": "CA",
      "jurisdiction_name": "California",
      "region": "US",
      "license_group": "Social Work",
      "license": "LCSW (Licensed Clinical Social Worker)",
      "change_type": "amended",
      "material": true,
      "event_at": "2026-09-03T13:20:00.000Z",
      "diff": {
        "total_hours": {
          "from": 36,
          "to": 40
        },
        "live_hours": {
          "from": 0,
          "to": 6
        }
      },
      "current": {
        "jurisdiction": {
          "code": "CA",
          "name": "California",
          "region": "US",
          "board": "Board of Behavioral Sciences"
        },
        "license_group": "Social Work",
        "license": "LCSW (Licensed Clinical Social Worker)",
        "cpd": false,
        "total_hours": 40,
        "cycle_years": 2,
        "live_interactive_required_hours": 6,
        "fully_async_ok": false,
        "home_study_cap": "The board's statement on self-study limits, as plain text.",
        "required_topics": [
          {
            "topic": "Law and Ethics",
            "hours": 6,
            "note": "Every renewal."
          }
        ],
        "board_nuances": "The board's own notes: exemptions, deadlines, anything that is not a number.",
        "source_urls": [
          "https://www.bbs.ca.gov/"
        ],
        "confidence": "medium",
        "verified_at": null,
        "effective_from": "2026-09-03T13:20:00.000Z",
        "effective_to": null,
        "is_current": true,
        "ingested_at": "2026-08-12T14:03:11.000Z"
      }
    }
  ],
  "since": "2026-09-01T00:00:00.000Z",
  "include": "material"
}

Reference lists

List jurisdictions

GET/v1/jurisdictions

Every jurisdiction Verbena serves, the 50 states and DC, with the license groups each currently has data for.

Query parameters

ParameterTypeDescription
region
query
array of string: US Regions. US is the only region served; any other value matches nothing.

Responses

  • 200 Jurisdictions in name order.
  • 304 Not modified: the If-None-Match ETag still matches. No body.
  • 401 The key is missing, unknown, revoked or expired. missing_api_key invalid_api_key
  • 403 The key belongs to an account whose plan does not include API access. plan_required
Request
curl -s "https://api.verbena.health/v1/jurisdictions" \
  -H "Authorization: Bearer $VERBENA_API_KEY"
Response 200
{
  "data": [
    {
      "code": "AL",
      "name": "Alabama",
      "region": "US",
      "board": "Alabama licensing board",
      "license_groups": [
        "BCBA",
        "Counseling",
        "MFT",
        "Psychology",
        "Social Work"
      ]
    }
  ]
}

List licenses

GET/v1/licenses

One row per license with a current requirement, with its jurisdiction and license group. Use it to fill a picker, or to find every state that has a given license with q. Unpaginated, because the list is bounded by the dataset.

Query parameters

ParameterTypeDescription
state
query
array of string Jurisdiction codes, case-insensitive. Repeat the parameter or use a comma list.
region
query
array of string: US Regions, case-insensitive. US is the only one; anything else is 400 unknown_region.
license_group
query
array of string: Social Work Counseling Psychology MFT BCBA License groups, case-insensitive. A value that is not one of the five is 400 unknown_license_group.
license
query
array of string An exact license label, matched case-insensitively. Repeat the parameter for several; labels can contain commas, so commas do not split.
q
query
string A case-insensitive substring of the license label, for example LCSW. Give it once.

Responses

  • 200 Licenses in jurisdiction, group and license order.
  • 304 Not modified: the If-None-Match ETag still matches. No body.
  • 400 A filter the endpoint cannot apply. unknown_region unknown_license_group bad_q bad_query
  • 401 The key is missing, unknown, revoked or expired. missing_api_key invalid_api_key
  • 403 The key belongs to an account whose plan does not include API access. plan_required
Request
curl -s "https://api.verbena.health/v1/licenses?q=LCSW" \
  -H "Authorization: Bearer $VERBENA_API_KEY"
Response 200
{
  "data": [
    {
      "jurisdiction": {
        "code": "CA",
        "name": "California",
        "region": "US",
        "board": "Board of Behavioral Sciences"
      },
      "license_group": "Social Work",
      "license": "LCSW (Licensed Clinical Social Worker)",
      "last_changed_at": "2026-08-12T14:03:11.000Z"
    }
  ]
}

List coverage

GET/v1/coverage

Every combination of jurisdiction and license group, covered or not, with its licenses and when anything in it last changed. The summary counts the rows returned. license and q belong to /licenses and are refused here.

Query parameters

ParameterTypeDescription
state
query
array of string Jurisdiction codes, case-insensitive. Repeat the parameter or use a comma list.
region
query
array of string: US Regions, case-insensitive. US is the only one; anything else is 400 unknown_region.
license_group
query
array of string: Social Work Counseling Psychology MFT BCBA License groups, case-insensitive. A value that is not one of the five is 400 unknown_license_group.
covered
query
boolean true or false keeps one side; anything else is 400 bad_covered.

Responses

  • 200 Coverage rows and their summary.
  • 304 Not modified: the If-None-Match ETag still matches. No body.
  • 400 A filter the endpoint cannot apply. unknown_region unknown_license_group bad_covered unsupported_filter
  • 401 The key is missing, unknown, revoked or expired. missing_api_key invalid_api_key
  • 403 The key belongs to an account whose plan does not include API access. plan_required
Request
curl -s "https://api.verbena.health/v1/coverage?state=CA" \
  -H "Authorization: Bearer $VERBENA_API_KEY"
Response 200
{
  "data": [
    {
      "jurisdiction": {
        "code": "CA",
        "name": "California",
        "region": "US",
        "board": "Board of Behavioral Sciences"
      },
      "license_group": "Social Work",
      "covered": true,
      "licenses": [
        "LCSW (Licensed Clinical Social Worker)"
      ],
      "last_changed_at": "2026-08-12T14:03:11.000Z"
    }
  ],
  "summary": {
    "combinations": 255,
    "covered": 255,
    "not_covered": 0
  }
}

List license groups

GET/v1/license-groups

The five license groups, with how many jurisdictions and licenses each covers now.

Query parameters

ParameterTypeDescription
region
query
array of string: US Regions, case-insensitive. US is the only one; anything else is 400 unknown_region.

Responses

  • 200 The five groups in alphabetical order.
  • 304 Not modified: the If-None-Match ETag still matches. No body.
  • 400 An unknown region. unknown_region
  • 401 The key is missing, unknown, revoked or expired. missing_api_key invalid_api_key
  • 403 The key belongs to an account whose plan does not include API access. plan_required
Request
curl -s "https://api.verbena.health/v1/license-groups" \
  -H "Authorization: Bearer $VERBENA_API_KEY"
Response 200
{
  "data": [
    {
      "license_group": "Social Work",
      "jurisdictions_covered": 51,
      "licenses": 51
    }
  ]
}

List topics

GET/v1/topics

The canonical topic vocabulary. Boards name one subject many ways, so each topic has a key, a label and the alternate wordings that mean it. To resolve a record's required_topics[].topic, match it against each topic's label and aliases together, ignoring case and repeated spaces. Most wordings resolve; a few have no key yet.

Query parameters

No parameters.

Responses

  • 200 Topics in curated order.
  • 304 Not modified: the If-None-Match ETag still matches. No body.
  • 401 The key is missing, unknown, revoked or expired. missing_api_key invalid_api_key
  • 403 The key belongs to an account whose plan does not include API access. plan_required
Request
curl -s "https://api.verbena.health/v1/topics" \
  -H "Authorization: Bearer $VERBENA_API_KEY"
Response 200
{
  "data": [
    {
      "key": "ethics",
      "label": "Ethics",
      "aliases": [
        "Ethics and Jurisprudence",
        "Ethical Practice of Psychology"
      ]
    }
  ]
}

Get the dataset summary

GET/v1/meta

Counts, when requirements last changed, and the closed value sets a client can validate against. dataset.last_changed_at moves when a requirement version is added, amended or retired. It does not move when a jurisdiction name or board is edited, so keep a scheduled full pull as well.

Query parameters

No parameters.

Responses

  • 200 The summary.
  • 304 Not modified: the If-None-Match ETag still matches. No body.
  • 401 The key is missing, unknown, revoked or expired. missing_api_key invalid_api_key
  • 403 The key belongs to an account whose plan does not include API access. plan_required
Request
curl -s "https://api.verbena.health/v1/meta" \
  -H "Authorization: Bearer $VERBENA_API_KEY"
Response 200
{
  "data": {
    "api_version": "v1",
    "dataset": {
      "last_changed_at": "2026-08-12T14:03:11.000Z",
      "jurisdictions": 51,
      "jurisdictions_covered": 51,
      "license_groups": 5,
      "combinations": 255,
      "combinations_covered": 255,
      "current_records": 255,
      "record_versions": 255
    },
    "values": {
      "regions": [
        "US"
      ],
      "license_groups": [
        "BCBA",
        "Counseling",
        "MFT",
        "Psychology",
        "Social Work"
      ],
      "confidence": [
        "high",
        "medium",
        "low",
        "unverified"
      ],
      "change_types": [
        "added",
        "amended",
        "retired"
      ]
    }
  }
}

Objects

Requirement

The continuing education rule for one license in one jurisdiction, as one version.

FieldTypeDescription
jurisdiction Jurisdiction
license_group string: Social Work Counseling Psychology MFT BCBA One of five license groups.
license string The license label, usually the abbreviation then the full name. With the jurisdiction code and license group, it identifies the record across versions.
cpd boolean Derived: true when total_hours is null, a regime with no fixed hours.
total_hours number or null Hours per renewal cycle. Null means no fixed hours, not missing data.
cycle_years number or null Length of the renewal cycle in years.
live_interactive_required_hours number The minimum hours that must be live or interactive.
fully_async_ok boolean Derived: true when there is no live minimum.
home_study_cap string or null The board's statement on self-study limits, as plain text.
required_topics array of RequiredTopic
board_nuances string or null The board's own notes: exemptions, deadlines and anything that does not fit a number.
source_urls array of string Where the rule is published. Every record has at least one.
confidence string: high medium low unverified high: every core value was checked against a primary source and dated. medium or low: published with less certainty. unverified: not yet checked against its source.
verified_at string or null When the values were last checked against their source.
effective_from string When this version was recorded. Not the board's effective date; that is in the notes where the board states one.
effective_to string or null When this version was closed; null while it is in force.
is_current boolean
ingested_at string

RequiredTopic

FieldTypeDescription
topic string The board's wording. Resolve it with /topics.
hours optional number or null Hours required for the topic, where the board states a number.
note optional string When it applies, for example every renewal or the first renewal only.

Change

FieldTypeDescription
jurisdiction string Jurisdiction code.
jurisdiction_name string
region string: US
license_group string: Social Work Counseling Psychology MFT BCBA One of five license groups.
license string
change_type string: added amended retired
material boolean True when a requirement was added or retired, or a rule field or the board notes moved.
event_at string effective_from for added and amended rows, effective_to for retired ones.
diff object or null For amended rows, each changed field as {from, to}. Keys use storage names: live_hours is live_interactive_required_hours on the record.
current Requirement The continuing education rule for one license in one jurisdiction, as one version.

License

FieldTypeDescription
jurisdiction Jurisdiction
license_group string: Social Work Counseling Psychology MFT BCBA One of five license groups.
license string
last_changed_at string When this license's current version took effect.

CoverageRow

FieldTypeDescription
jurisdiction Jurisdiction
license_group string: Social Work Counseling Psychology MFT BCBA One of five license groups.
covered boolean
licenses array of string Current licenses in the combination, sorted; empty when not covered.
last_changed_at string or null The latest addition, amendment or retirement in the combination; null if it never had a record.

CoverageSummary

FieldTypeDescription
combinations integer
covered integer
not_covered integer

LicenseGroupSummary

FieldTypeDescription
license_group string: Social Work Counseling Psychology MFT BCBA One of five license groups.
jurisdictions_covered integer
licenses integer

Topic

FieldTypeDescription
key string
label string
aliases array of string Other wordings boards use for the topic.

Meta

FieldTypeDescription
api_version string: v1
dataset object
values object

Jurisdiction

FieldTypeDescription
code string Jurisdiction code, for example CA.
name string
region string: US
board string or null The licensing board, where known.

Error

FieldTypeDescription
error string A stable code to branch on.
detail optional string A human-readable explanation. Do not parse it.
jurisdiction optional string On unknown_jurisdiction, the code that was not found.