{"server":"com.reqbeat/hiring-signals","count":34,"changes":[{"tool":"search_jobs","kind":"changed","observed_at":"2026-10-19T11:00:13.469Z","fields":["description","inputSchema"],"description_before":"Flat, role-granular job search -- the individual open roles across\n    companies matching `function` / `geo` (country) / `since`, one\n    row per logical req (each with its own `company_id` + `req_key`),\n    LinkedIn-excluded (ATS tenants plus public job boards and aggregators; each row's `board` names its source) +\n    freshness-floored. `since` filters on `first_seen`, our first\n    observation of the req (not the employer's posting date); each row's\n    `source_posted_at` is the date the source itself published, null when it\n    gave none. Keyset-paginated via the opaque `cursor`\n    (a prior call's `next_cursor`). Use `who_is_hiring_for` for the\n    company-granular reverse view. `function` is a function name (a prior\n    result's `function_name`, like 'Software & IT') or a function id (its\n    `function`); anything else, like 'engineering', is rejected with an\n    explicit error that lists the names, rather than an empty result -- pass plain\n    language as `q` instead, which searches the posting's own title,\n    expanded semantically to nearby titles, and reports each row's\n    `relevance` (0-1). `q` is independent of `function`: pass both to search\n    titles within one function. `sort` is 'relevance' (the default with a\n    `q`) or 'recency'; omit both and the page keeps its stable default\n    order. `limit` is bounded: an oversized page is rejected rather than\n    truncated, so page through the full set with `cursor` instead of\n    raising `limit`. No key yet? The call answers with a signup link\n    instead of rows.","description_after":"Flat, role-granular job search -- the individual open roles across\n    companies matching `function` / `geo` (country) / `since`, one\n    row per logical req (each with its own `company_id` + `req_key`),\n    LinkedIn-excluded (ATS tenants plus public job boards and aggregators; each row's `board` names its source) +\n    freshness-floored. `since` filters on `first_seen`, our first\n    observation of the req (not the employer's posting date); each row's\n    `source_posted_at` is the date the source itself published, null when it\n    gave none. Keyset-paginated via the opaque `cursor`\n    (a prior call's `next_cursor`). Use `who_is_hiring_for` for the\n    company-granular reverse view. `function` is a function name (a prior\n    result's `function_name`, like 'Software & IT') or a function id (its\n    `function`); anything else, like 'engineering', is rejected with an\n    explicit error that lists the names, rather than an empty result -- pass plain\n    language as `q` instead, which searches the posting's own title,\n    expanded semantically to nearby titles, and reports each row's\n    `relevance` (0-1). `exclude_employer_types` (e.g. ['staffing']) drops\n    roles whose posting is classified as that employer type -- 'direct',\n    'staffing', 'consultancy' or 'unknown'; unclassified roles are kept unless\n    'unknown' is listed. `q` is independent of `function`: pass both to search\n    titles within one function. `sort` is 'relevance' (the default with a\n    `q`) or 'recency'; omit both and the page keeps its stable default\n    order. `limit` is bounded: an oversized page is rejected rather than\n    truncated, so page through the full set with `cursor` instead of\n    raising `limit`. No key yet? The call answers with a signup link\n    instead of rows.","description_similarity":0.892,"before_hash":"741aef15fe9efefbca221affd1b41e34","after_hash":"d5d80fdd994357ce2a59442039cad0ea"},{"tool":"register_webhook","kind":"changed","observed_at":"2026-10-15T20:45:19.545Z","fields":["description"],"description_before":"Register the delivery target a watch fires to, and get back the\n    `webhook_endpoint_id` `watch_company` needs -- call this first if you\n    do not already hold one. Idempotent: registering the same `url` twice\n    returns the same id, so retrying is safe and never leaves you with two\n    endpoints. `secret` is optional; supply one to verify the\n    `X-Plane-Signature` on delivered payloads, omit it and one is\n    generated (it is never returned). Registration itself is free -- the\n    `watch_company` call that follows is what bills.","description_after":"Register the delivery target a watch fires to, and get back the\n    `webhook_endpoint_id` `watch_company` needs -- call this first if you\n    do not already hold one. Idempotent: registering the same `url` twice\n    returns the same id, so retrying is safe and never leaves you with two\n    endpoints. `secret` is optional; supply one to verify the\n    `X-Reqbeat-Signature` on delivered payloads, omit it and one is\n    generated and returned once in `secret` (never again after this call).\n    Registration itself is free -- the `watch_company` call that follows is\n    what bills.","description_similarity":0.91,"before_hash":"90e76e8e649f6990750f776f5d7839b3","after_hash":"df82944fe61aee445eedb76a6d500bf9"},{"tool":"write_outcome","kind":"changed","observed_at":"2026-10-09T21:49:43.356Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"06022d34aa1a9e68e073deb1d8fc4f12","after_hash":"3b710fef89cbba275791b667f0848e1b"},{"tool":"cancel_watch","kind":"changed","observed_at":"2026-10-09T21:49:43.356Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"63bbad2a2ea0cc806f8b83a94d5b7c31","after_hash":"2c1a9a3ad2fb0612597a4a752103f5a0"},{"tool":"list_watches","kind":"changed","observed_at":"2026-10-09T21:49:43.356Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"2dcebff1c29c7944b62f39d5a98e01e4","after_hash":"5d051de18db157a3b64a21fe852baca7"},{"tool":"watch_company","kind":"changed","observed_at":"2026-10-09T21:49:43.356Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"0b9972a17e5ccf94001e63d014ec7a26","after_hash":"d3e53665e55a6f2667fa1779b47a6c47"},{"tool":"register_webhook","kind":"changed","observed_at":"2026-10-09T21:49:43.356Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"3128cd07236dfac8aec8b676a3951f12","after_hash":"90e76e8e649f6990750f776f5d7839b3"},{"tool":"find_company","kind":"changed","observed_at":"2026-10-09T21:49:43.356Z","fields":["description","inputSchema"],"description_before":"WHEN you hold a company's website or name but not the `company_id`\n    every company-scoped tool takes (`is_hiring`, `get_open_reqs`,\n    `hiring_pulse`, `pre_action_brief`, `watch_company`). Pass exactly one of\n    `domain` or `name`; both or neither is an error naming that rule.\n    `domain` takes a bare host or a full URL and matches exactly\n    ({\"domain\": \"https://www.stripe.com/jobs\"} -> the companies at\n    `stripe.com`); `name` returns up to five candidates, each with a\n    `match_confidence` -- 1.0 for an exact name, 0.8 for a match once legal\n    suffixes are dropped. Each company carries `company_id`, `company_name`,\n    `company_domain`, `country_code` and `coverage_status`, and no hiring\n    signal: ask `is_hiring` for that. Nothing matching is an empty\n    `companies` list, never an error. Never billed. No key yet? On the hosted\n    HTTP endpoint send no `X-API-Key` header and the lookup runs on a shared\n    demo credential until a per-IP limit is reached.","description_after":"WHEN you hold a company's website or name but not the `company_id`\n    every company-scoped tool takes (`is_hiring`, `get_open_reqs`,\n    `hiring_pulse`, `pre_action_brief`, `watch_company`). Pass exactly one of\n    `domain` or `name`; both or neither is an error naming that rule.\n    `domain` takes a bare host or a full URL and matches exactly\n    ({\"domain\": \"https://www.stripe.com/jobs\"} -> the companies at\n    `stripe.com`); `name` returns up to five candidates, each with a\n    `match_confidence` -- 1.0 for an exact name, 0.8 for a match once legal\n    suffixes are dropped. Each company carries `company_id`, `company_name`,\n    `company_domain`, `country_code` and `coverage_status`, and no hiring\n    signal: ask `is_hiring` for that. Nothing matching is an empty\n    `companies` list, never an error. Never billed. No key yet? The call\n    answers with a signup link instead of companies.","description_similarity":0.791,"before_hash":"0f9ecf996bf57b025fbe183b99dd3488","after_hash":"aefe990eef75bb2db2b9cb9ce0d6c94b"},{"tool":"get_changes","kind":"changed","observed_at":"2026-10-09T21:49:43.356Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"d24b164bc20baa0e7fef8fa8221de330","after_hash":"fbf1d135455ae4539a2e9cf0eb5c5a2c"},{"tool":"pre_action_brief","kind":"changed","observed_at":"2026-10-09T21:49:43.356Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"00b3993c3301d582f3a110b19608623c","after_hash":"3463e1fc209179d7eec0644874800964"},{"tool":"find_qualified_reqs","kind":"changed","observed_at":"2026-10-09T21:49:43.356Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"57d5d6fda71c536c1c479f56f024a6fa","after_hash":"84cf74dfcd2fe1246a8498e79e720202"},{"tool":"get_role","kind":"changed","observed_at":"2026-10-09T21:49:43.356Z","fields":["description","inputSchema"],"description_before":"One open role's detail, addressed by the `company_id` + `req_key`\n    pair every `search_jobs` row already carries -- the follow-up call\n    for a role you hold an identifier for, instead of re-pulling the whole\n    company with `get_open_reqs`. Scoped exactly as `search_jobs` is:\n    LinkedIn-excluded (ATS tenants plus public job boards and aggregators) and freshness-floored. The body adds `raw_title` (the\n    posting's own title) and `boards`, the full deduped list of boards\n    reporting this req. A role that does not exist, is closed, or has not\n    reached the freshness floor is an explicit error, never an empty\n    success -- and it is not billed. No key yet? On the hosted HTTP\n    endpoint the first calls are free: send no `X-API-Key` header and\n    the lookup runs on a shared demo credential, billed to\n    nobody and marked as such, until a per-IP limit is reached.","description_after":"One open role's detail, addressed by the `company_id` + `req_key`\n    pair every `search_jobs` row already carries -- the follow-up call\n    for a role you hold an identifier for, instead of re-pulling the whole\n    company with `get_open_reqs`. Scoped exactly as `search_jobs` is:\n    LinkedIn-excluded (ATS tenants plus public job boards and aggregators) and freshness-floored. The body adds `raw_title` (the\n    posting's own title) and `boards`, the full deduped list of boards\n    reporting this req. A role that does not exist, is closed, or has not\n    reached the freshness floor is an explicit error, never an empty\n    success -- and it is not billed. No key yet? The call answers with a\n    signup link instead of the role.","description_similarity":0.743,"before_hash":"3bc99e869df9f3095cd1057338fc25c9","after_hash":"94344f008c987634585e5ef1ab991243"},{"tool":"search_jobs","kind":"changed","observed_at":"2026-10-09T21:49:43.356Z","fields":["description","inputSchema"],"description_before":"Flat, role-granular job search -- the individual open roles across\n    companies matching `function` / `geo` (country) / `since`, one\n    row per logical req (each with its own `company_id` + `req_key`),\n    LinkedIn-excluded (ATS tenants plus public job boards and aggregators; each row's `board` names its source) +\n    freshness-floored. `since` filters on `first_seen`, our first\n    observation of the req (not the employer's posting date); each row's\n    `source_posted_at` is the date the source itself published, null when it\n    gave none. Keyset-paginated via the opaque `cursor`\n    (a prior call's `next_cursor`). Use `who_is_hiring_for` for the\n    company-granular reverse view. `function` is a function name (a prior\n    result's `function_name`, like 'Software & IT') or a function id (its\n    `function`); anything else, like 'engineering', is rejected with an\n    explicit error that lists the names, rather than an empty result -- pass plain\n    language as `q` instead, which searches the posting's own title,\n    expanded semantically to nearby titles, and reports each row's\n    `relevance` (0-1). `q` is independent of `function`: pass both to search\n    titles within one function. `sort` is 'relevance' (the default with a\n    `q`) or 'recency'; omit both and the page keeps its stable default\n    order. `limit` is bounded: an oversized page is rejected rather than\n    truncated, so page through the full set with `cursor` instead of\n    raising `limit`. No key yet? On the hosted HTTP endpoint the first\n    calls are free: send no `X-API-Key` header and the search\n    runs on a shared demo credential -- a smaller page, billed to nobody,\n    and the result says so -- until a per-IP limit is reached, after which\n    the answer becomes a signup link whose minted key finishes this exact\n    search. On any other transport a blank key answers with that signup\n    link straight away.","description_after":"Flat, role-granular job search -- the individual open roles across\n    companies matching `function` / `geo` (country) / `since`, one\n    row per logical req (each with its own `company_id` + `req_key`),\n    LinkedIn-excluded (ATS tenants plus public job boards and aggregators; each row's `board` names its source) +\n    freshness-floored. `since` filters on `first_seen`, our first\n    observation of the req (not the employer's posting date); each row's\n    `source_posted_at` is the date the source itself published, null when it\n    gave none. Keyset-paginated via the opaque `cursor`\n    (a prior call's `next_cursor`). Use `who_is_hiring_for` for the\n    company-granular reverse view. `function` is a function name (a prior\n    result's `function_name`, like 'Software & IT') or a function id (its\n    `function`); anything else, like 'engineering', is rejected with an\n    explicit error that lists the names, rather than an empty result -- pass plain\n    language as `q` instead, which searches the posting's own title,\n    expanded semantically to nearby titles, and reports each row's\n    `relevance` (0-1). `q` is independent of `function`: pass both to search\n    titles within one function. `sort` is 'relevance' (the default with a\n    `q`) or 'recency'; omit both and the page keeps its stable default\n    order. `limit` is bounded: an oversized page is rejected rather than\n    truncated, so page through the full set with `cursor` instead of\n    raising `limit`. No key yet? The call answers with a signup link\n    instead of rows.","description_similarity":0.794,"before_hash":"7f10bd17005c93800af67c1c9c7024c0","after_hash":"741aef15fe9efefbca221affd1b41e34"},{"tool":"who_is_hiring_for","kind":"changed","observed_at":"2026-10-09T21:49:43.356Z","fields":["description","inputSchema"],"description_before":"WHEN an agent needs to FIND the companies worth working -- the sourcing step, before it knows which companies exist. Reverse who's-hiring-for {title, geo} search: companies with active reqs matching `q`/`geo`/`since`, deduped by company, keyset-paginated via `cursor`. `q` is free text matched against the posting title, not an id; plurals and other inflections match, so \"backend engineers\" is the same search. `geo` is resolved to a stored country before matching; an unresolvable one is an explicit error, never a quietly partial page. `limit` is bounded -- page through the full set with `cursor` instead of raising it. Billed per company returned (~0.10 USD each) -- an empty result bills nothing. q=\"backend engineer\", geo=\"USA\" -> the companies with matching active reqs, each with its pulse and its matched reqs. geo=\"Atlantis\" -> an explicit unresolvable-country error rather than an empty page. No key yet? On the hosted HTTP endpoint the first calls are free: pass `plane_api_key` as an empty string and the search runs on a shared demo credential -- a smaller page, billed to nobody -- until a per-IP limit is reached, after which the answer becomes a signup link whose minted key finishes this exact search. On any other transport a blank key answers with that signup link straight away. Already holding a company_id and only need a yes/no? Use `is_hiring`.","description_after":"WHEN an agent needs to FIND the companies worth working -- the sourcing step, before it knows which companies exist. Reverse who's-hiring-for {title, geo} search: companies with active reqs matching `q`/`geo`/`since`, deduped by company, keyset-paginated via `cursor`. `q` is free text matched against the posting title, not an id; plurals and other inflections match, so \"backend engineers\" is the same search. `geo` is resolved to a stored country before matching; an unresolvable one is an explicit error, never a quietly partial page. `limit` is bounded -- page through the full set with `cursor` instead of raising it. Billed per company returned (~0.10 USD each) -- an empty result bills nothing. q=\"backend engineer\", geo=\"USA\" -> the companies with matching active reqs, each with its pulse and its matched reqs. geo=\"Atlantis\" -> an explicit unresolvable-country error rather than an empty page. No key yet? Pass `plane_api_key` as an empty string and the call answers with a signup link instead of rows; on the hosted HTTP endpoint the key it mints finishes this exact search. Already holding a company_id and only need a yes/no? Use `is_hiring`.","description_similarity":0.818,"before_hash":"229bc5eb9f85f827e03dc0653dc0b451","after_hash":"14ca8bbc259f53dc14caff46ffc35913"},{"tool":"hiring_pulse","kind":"changed","observed_at":"2026-10-09T21:49:43.356Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"02c46c5017ae2e83714fc45c998927bb","after_hash":"36d8ce28c8b5f7fcfadbeb610fd50202"},{"tool":"get_open_reqs","kind":"changed","observed_at":"2026-10-09T21:49:43.356Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"78224464982c7e88d4c4bf9285026afa","after_hash":"6e6148dd9f39852538f58aed82bb5520"},{"tool":"is_hiring","kind":"changed","observed_at":"2026-10-09T21:49:43.356Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"7e7115f02daa1769e849b18c8b598129","after_hash":"69f414e4a8e8b6c7351369e6141e763d"},{"tool":"search_jobs","kind":"changed","observed_at":"2026-10-06T19:13:33.498Z","fields":["description"],"description_before":"Flat, role-granular job search -- the individual open roles across\n    companies matching `function` / `geo` (country) / `since`, one\n    row per logical req (each with its own `company_id` + `req_key`),\n    LinkedIn-excluded (ATS tenants plus public job boards and aggregators; each row's `board` names its source) +\n    freshness-floored. `since` filters on `first_seen`, our first\n    observation of the req (not the employer's posting date); each row's\n    `source_posted_at` is the date the source itself published, null when it\n    gave none. Keyset-paginated via the opaque `cursor`\n    (a prior call's `next_cursor`). Use `who_is_hiring_for` for the\n    company-granular reverse view. `function` must be a function id (as seen\n    in prior results); a plain function name like 'engineering' is rejected\n    with an explicit error rather than an empty result -- pass plain\n    language as `q` instead, which searches the posting's own title,\n    expanded semantically to nearby titles, and reports each row's\n    `relevance` (0-1). `q` is independent of `function`: pass both to search\n    titles within one function. `sort` is 'relevance' (the default with a\n    `q`) or 'recency'; omit both and the page keeps its stable default\n    order. `limit` is bounded: an oversized page is rejected rather than\n    truncated, so page through the full set with `cursor` instead of\n    raising `limit`. No key yet? On the hosted HTTP endpoint the first\n    calls are free: send no `X-API-Key` header and the search\n    runs on a shared demo credential -- a smaller page, billed to nobody,\n    and the result says so -- until a per-IP limit is reached, after which\n    the answer becomes a signup link whose minted key finishes this exact\n    search. On any other transport a blank key answers with that signup\n    link straight away.","description_after":"Flat, role-granular job search -- the individual open roles across\n    companies matching `function` / `geo` (country) / `since`, one\n    row per logical req (each with its own `company_id` + `req_key`),\n    LinkedIn-excluded (ATS tenants plus public job boards and aggregators; each row's `board` names its source) +\n    freshness-floored. `since` filters on `first_seen`, our first\n    observation of the req (not the employer's posting date); each row's\n    `source_posted_at` is the date the source itself published, null when it\n    gave none. Keyset-paginated via the opaque `cursor`\n    (a prior call's `next_cursor`). Use `who_is_hiring_for` for the\n    company-granular reverse view. `function` is a function name (a prior\n    result's `function_name`, like 'Software & IT') or a function id (its\n    `function`); anything else, like 'engineering', is rejected with an\n    explicit error that lists the names, rather than an empty result -- pass plain\n    language as `q` instead, which searches the posting's own title,\n    expanded semantically to nearby titles, and reports each row's\n    `relevance` (0-1). `q` is independent of `function`: pass both to search\n    titles within one function. `sort` is 'relevance' (the default with a\n    `q`) or 'recency'; omit both and the page keeps its stable default\n    order. `limit` is bounded: an oversized page is rejected rather than\n    truncated, so page through the full set with `cursor` instead of\n    raising `limit`. No key yet? On the hosted HTTP endpoint the first\n    calls are free: send no `X-API-Key` header and the search\n    runs on a shared demo credential -- a smaller page, billed to nobody,\n    and the result says so -- until a per-IP limit is reached, after which\n    the answer becomes a signup link whose minted key finishes this exact\n    search. On any other transport a blank key answers with that signup\n    link straight away.","description_similarity":0.955,"before_hash":"60795de231dd0866b9cb97afc0ffde6a","after_hash":"7f10bd17005c93800af67c1c9c7024c0"},{"tool":"get_open_reqs","kind":"changed","observed_at":"2026-10-06T19:13:33.498Z","fields":["description"],"description_before":"The company's current active reqs, deduped across boards --\n    LinkedIn-excluded: ATS tenants plus public job boards and aggregators; each row's `boards` names its source.\n    Freshness-floored. Each row's `first_seen` is our first observation of\n    the req, not the employer's posting date; `source_posted_at` is the date\n    the source itself published, null when it gave none. `function` must be a function id\n    (as seen in prior results); a plain role name like 'engineering' is\n    rejected with an explicit error rather than an empty result. `limit`\n    is bounded: an oversized page is rejected rather than truncated.","description_after":"The company's current active reqs, deduped across boards --\n    LinkedIn-excluded: ATS tenants plus public job boards and aggregators; each row's `boards` names its source.\n    Freshness-floored. Each row's `first_seen` is our first observation of\n    the req, not the employer's posting date; `source_posted_at` is the date\n    the source itself published, null when it gave none. `function` is a function name\n    (a prior result's `function_name`, like 'Software & IT') or a function id\n    (its `function`); anything else, like 'engineering', is\n    rejected with an explicit error that lists the names, rather than an empty result. `limit`\n    is bounded: an oversized page is rejected rather than truncated.","description_similarity":0.835,"before_hash":"6882493537bfe437ba6a7dd652607a2b","after_hash":"78224464982c7e88d4c4bf9285026afa"},{"tool":"search_jobs","kind":"changed","observed_at":"2026-10-06T13:27:16.680Z","fields":["description","inputSchema"],"description_before":"Flat, role-granular job search -- the individual open roles across\n    companies matching `role` (function) / `geo` (country) / `since`, one\n    row per logical req (each with its own `company_id` + `req_key`),\n    LinkedIn-excluded (ATS tenants plus public job boards and aggregators; each row's `board` names its source) +\n    freshness-floored. `since` filters on `first_seen`, our first\n    observation of the req (not the employer's posting date); each row's\n    `source_posted_at` is the date the source itself published, null when it\n    gave none. Keyset-paginated via the opaque `cursor`\n    (a prior call's `next_cursor`). Use `who_is_hiring_for` for the\n    company-granular reverse view. `role` must be a function id (as seen\n    in prior results); a plain role name like 'engineering' is rejected\n    with an explicit error rather than an empty result -- pass plain\n    language as `q` instead, which searches the posting's own title,\n    expanded semantically to nearby titles, and reports each row's\n    `relevance` (0-1). `q` is independent of `role`: pass both to search\n    titles within one function. `sort` is 'relevance' (the default with a\n    `q`) or 'recency'; omit both and the page keeps its stable default\n    order. `limit` is bounded: an oversized page is rejected rather than\n    truncated, so page through the full set with `cursor` instead of\n    raising `limit`. No key yet? On the hosted HTTP endpoint the first\n    calls are free: send no `X-API-Key` header and the search\n    runs on a shared demo credential -- a smaller page, billed to nobody,\n    and the result says so -- until a per-IP limit is reached, after which\n    the answer becomes a signup link whose minted key finishes this exact\n    search. On any other transport a blank key answers with that signup\n    link straight away.","description_after":"Flat, role-granular job search -- the individual open roles across\n    companies matching `function` / `geo` (country) / `since`, one\n    row per logical req (each with its own `company_id` + `req_key`),\n    LinkedIn-excluded (ATS tenants plus public job boards and aggregators; each row's `board` names its source) +\n    freshness-floored. `since` filters on `first_seen`, our first\n    observation of the req (not the employer's posting date); each row's\n    `source_posted_at` is the date the source itself published, null when it\n    gave none. Keyset-paginated via the opaque `cursor`\n    (a prior call's `next_cursor`). Use `who_is_hiring_for` for the\n    company-granular reverse view. `function` must be a function id (as seen\n    in prior results); a plain function name like 'engineering' is rejected\n    with an explicit error rather than an empty result -- pass plain\n    language as `q` instead, which searches the posting's own title,\n    expanded semantically to nearby titles, and reports each row's\n    `relevance` (0-1). `q` is independent of `function`: pass both to search\n    titles within one function. `sort` is 'relevance' (the default with a\n    `q`) or 'recency'; omit both and the page keeps its stable default\n    order. `limit` is bounded: an oversized page is rejected rather than\n    truncated, so page through the full set with `cursor` instead of\n    raising `limit`. No key yet? On the hosted HTTP endpoint the first\n    calls are free: send no `X-API-Key` header and the search\n    runs on a shared demo credential -- a smaller page, billed to nobody,\n    and the result says so -- until a per-IP limit is reached, after which\n    the answer becomes a signup link whose minted key finishes this exact\n    search. On any other transport a blank key answers with that signup\n    link straight away.","description_similarity":1,"before_hash":"4bff9ce8f88e03d66455996f13ad2299","after_hash":"60795de231dd0866b9cb97afc0ffde6a"},{"tool":"who_is_hiring_for","kind":"changed","observed_at":"2026-10-06T13:27:16.680Z","fields":["description","inputSchema"],"description_before":"WHEN an agent needs to FIND the companies worth working -- the sourcing step, before it knows which companies exist. Reverse who's-hiring-for {role, geo} search: companies with active reqs matching `role`/`geo`/`since`, deduped by company, keyset-paginated via `cursor`. `role` is free text matched against the posting title, not an id; plurals and other inflections match, so \"backend engineers\" is the same search. `geo` is resolved to a stored country before matching; an unresolvable one is an explicit error, never a quietly partial page. `limit` is bounded -- page through the full set with `cursor` instead of raising it. Billed per company returned (~0.10 USD each) -- an empty result bills nothing. role=\"backend engineer\", geo=\"USA\" -> the companies with matching active reqs, each with its pulse and its matched reqs. geo=\"Atlantis\" -> an explicit unresolvable-country error rather than an empty page. No key yet? On the hosted HTTP endpoint the first calls are free: pass `plane_api_key` as an empty string and the search runs on a shared demo credential -- a smaller page, billed to nobody -- until a per-IP limit is reached, after which the answer becomes a signup link whose minted key finishes this exact search. On any other transport a blank key answers with that signup link straight away. Already holding a company_id and only need a yes/no? Use `is_hiring`.","description_after":"WHEN an agent needs to FIND the companies worth working -- the sourcing step, before it knows which companies exist. Reverse who's-hiring-for {title, geo} search: companies with active reqs matching `q`/`geo`/`since`, deduped by company, keyset-paginated via `cursor`. `q` is free text matched against the posting title, not an id; plurals and other inflections match, so \"backend engineers\" is the same search. `geo` is resolved to a stored country before matching; an unresolvable one is an explicit error, never a quietly partial page. `limit` is bounded -- page through the full set with `cursor` instead of raising it. Billed per company returned (~0.10 USD each) -- an empty result bills nothing. q=\"backend engineer\", geo=\"USA\" -> the companies with matching active reqs, each with its pulse and its matched reqs. geo=\"Atlantis\" -> an explicit unresolvable-country error rather than an empty page. No key yet? On the hosted HTTP endpoint the first calls are free: pass `plane_api_key` as an empty string and the search runs on a shared demo credential -- a smaller page, billed to nobody -- until a per-IP limit is reached, after which the answer becomes a signup link whose minted key finishes this exact search. On any other transport a blank key answers with that signup link straight away. Already holding a company_id and only need a yes/no? Use `is_hiring`.","description_similarity":0.986,"before_hash":"1731c7e95401b8f4e5909bcab12d447c","after_hash":"229bc5eb9f85f827e03dc0653dc0b451"},{"tool":"watch_company","kind":"changed","observed_at":"2026-10-06T07:01:14.399Z","fields":["description","inputSchema"],"description_before":"Subscribe to a company's hiring events on a registered webhook --\n    `webhook_endpoint_id` must belong to the same customer as the\n    authenticated key. Meters one `watch` unit.\n\n    A free key holds a limited number of watches at once; the one past that\n    is refused with the same 402 the REST route raises, and cancelling a\n    watch returns the slot.","description_after":"Subscribe to a company's hiring events on a registered webhook --\n    `webhook_endpoint_id` must belong to the same customer as the\n    authenticated key. Meters one `watch` unit.\n\n    `event_types` names which events fire it, at least one of: `opened` (a\n    req seen for the first time), `reobserved` (a known req seen again on a\n    later day), `reposted` (a req that came back after it was gone), `closed`\n    (a req verified gone from its source). Anything else is refused and\n    creates nothing: a watch on a type that never fires would be billed and\n    silent.\n\n    A free key holds a limited number of watches at once; the one past that\n    is refused with the same 402 the REST route raises, and cancelling a\n    watch returns the slot.","description_similarity":0.529,"before_hash":"7e4ab65d49b49973894527a4577bf01a","after_hash":"0b9972a17e5ccf94001e63d014ec7a26"},{"tool":"find_qualified_reqs","kind":"changed","observed_at":"2026-10-06T07:01:14.399Z","fields":["description"],"description_before":"WHEN an agent already knows its ideal customer profile and wants the\n    matching open roles as rows it can act on: several countries, an\n    industry, a headcount band and title keywords in ONE call, instead of a\n    search followed by a lookup per company. `criteria` takes up to three\n    groups -- `company` (country, industry, industry_terms, headcount_band,\n    company_kind), `req` (raw_title, title_excludes, seniority_level,\n    job_family, skills, remote_type, location) and `event` (company_id,\n    board, source_type, ats_vendor, country) -- AND across fields, OR within\n    one.\n    A field outside that list is an explicit error, never quietly dropped.\n    criteria={\"company\": {\"country\": [\"United States\", \"Germany\"]},\n    \"req\": {\"raw_title\": [\"backend engineer\"]}} -> live backend roles in\n    both countries, each row naming the company and carrying the posting\n    URL, seniority, skills and declared or estimated yearly pay.\n    `salary_min_usd` / `salary_max_usd` bracket that pay. Agencies and\n    expired postings are excluded by default. Page with `cursor` (the\n    previous `next_cursor`); `limit` is bounded. Billed per row returned, and\n    an empty page bills nothing. Needs an API key: without one the answer is\n    a signup link. For a first look at who is hiring before you have a key,\n    use `who_is_hiring_for`.","description_after":"WHEN an agent already knows its ideal customer profile and wants the\n    matching open roles as rows it can act on: several countries, an\n    industry, a headcount band and title keywords in ONE call, instead of a\n    search followed by a lookup per company. `criteria` takes up to three\n    groups -- `company` (country, industry, industry_terms, headcount_band,\n    company_kind), `req` (q, q_excludes, seniority_level, function,\n    skills, remote_type, location) and `event` (company_id,\n    board, source_type, ats_vendor, country) -- AND across fields, OR within\n    one.\n    A field outside that list is an explicit error, never quietly dropped.\n    criteria={\"company\": {\"country\": [\"United States\", \"Germany\"]},\n    \"req\": {\"q\": [\"backend engineer\"]}} -> live backend roles in\n    both countries, each row naming the company and carrying the posting\n    URL, seniority, skills and declared or estimated yearly pay.\n    `salary_min_usd` / `salary_max_usd` bracket that pay. Agencies and\n    expired postings are excluded by default. Page with `cursor` (the\n    previous `next_cursor`); `limit` is bounded. Billed per row returned, and\n    an empty page bills nothing. Needs an API key: without one the answer is\n    a signup link. For a first look at who is hiring before you have a key,\n    use `who_is_hiring_for`.","description_similarity":0.964,"before_hash":"480a46bc1ba434fa87bbf923db2e9f63","after_hash":"57d5d6fda71c536c1c479f56f024a6fa"},{"tool":"who_is_hiring_for","kind":"changed","observed_at":"2026-10-06T07:01:14.399Z","fields":["description"],"description_before":"WHEN an agent needs to FIND the companies worth working -- the sourcing step, before it knows which companies exist. Reverse who's-hiring-for {role, geo} search: companies with active reqs matching `role`/`geo`/`since`, deduped by company, keyset-paginated via `cursor`. `role` is free text matched against the posting title, not an id. `geo` is resolved to a stored country before matching; an unresolvable one is an explicit error, never a quietly partial page. `limit` is bounded -- page through the full set with `cursor` instead of raising it. Billed per company returned (~0.10 USD each) -- an empty result bills nothing. role=\"backend engineer\", geo=\"USA\" -> the companies with matching active reqs, each with its pulse and its matched reqs. geo=\"Atlantis\" -> an explicit unresolvable-country error rather than an empty page. No key yet? On the hosted HTTP endpoint the first calls are free: pass `plane_api_key` as an empty string and the search runs on a shared demo credential -- a smaller page, billed to nobody -- until a per-IP limit is reached, after which the answer becomes a signup link whose minted key finishes this exact search. On any other transport a blank key answers with that signup link straight away. Already holding a company_id and only need a yes/no? Use `is_hiring`.","description_after":"WHEN an agent needs to FIND the companies worth working -- the sourcing step, before it knows which companies exist. Reverse who's-hiring-for {role, geo} search: companies with active reqs matching `role`/`geo`/`since`, deduped by company, keyset-paginated via `cursor`. `role` is free text matched against the posting title, not an id; plurals and other inflections match, so \"backend engineers\" is the same search. `geo` is resolved to a stored country before matching; an unresolvable one is an explicit error, never a quietly partial page. `limit` is bounded -- page through the full set with `cursor` instead of raising it. Billed per company returned (~0.10 USD each) -- an empty result bills nothing. role=\"backend engineer\", geo=\"USA\" -> the companies with matching active reqs, each with its pulse and its matched reqs. geo=\"Atlantis\" -> an explicit unresolvable-country error rather than an empty page. No key yet? On the hosted HTTP endpoint the first calls are free: pass `plane_api_key` as an empty string and the search runs on a shared demo credential -- a smaller page, billed to nobody -- until a per-IP limit is reached, after which the answer becomes a signup link whose minted key finishes this exact search. On any other transport a blank key answers with that signup link straight away. Already holding a company_id and only need a yes/no? Use `is_hiring`.","description_similarity":0.957,"before_hash":"ddaa22f2a9c9c0f141ea5e1495a23b02","after_hash":"1731c7e95401b8f4e5909bcab12d447c"},{"tool":"find_qualified_reqs","kind":"added","observed_at":"2026-10-06T00:35:21.648Z","fields":[],"description_before":null,"description_after":"WHEN an agent already knows its ideal customer profile and wants the\n    matching open roles as rows it can act on: several countries, an\n    industry, a headcount band and title keywords in ONE call, instead of a\n    search followed by a lookup per company. `criteria` takes up to three\n    groups -- `company` (country, industry, industry_terms, headcount_band,\n    company_kind), `req` (raw_title, title_excludes, seniority_level,\n    job_family, skills, remote_type, location) and `event` (company_id,\n    board, source_type, ats_vendor, country) -- AND across fields, OR within\n    one.\n    A field outside that list is an explicit error, never quietly dropped.\n    criteria={\"company\": {\"country\": [\"United States\", \"Germany\"]},\n    \"req\": {\"raw_title\": [\"backend engineer\"]}} -> live backend roles in\n    both countries, each row naming the company and carrying the posting\n    URL, seniority, skills and declared or estimated yearly pay.\n    `salary_min_usd` / `salary_max_usd` bracket that pay. Agencies and\n    expired postings are excluded by default. Page with `cursor` (the\n    previous `next_cursor`); `limit` is bounded. Billed per row returned, and\n    an empty page bills nothing. Needs an API key: without one the answer is\n    a signup link. For a first look at who is hiring before you have a key,\n    use `who_is_hiring_for`.","description_similarity":null,"before_hash":null,"after_hash":"480a46bc1ba434fa87bbf923db2e9f63"},{"tool":"get_role","kind":"changed","observed_at":"2026-10-06T00:35:21.648Z","fields":["description"],"description_before":"One open role's detail, addressed by the `company_id` + `req_key`\n    pair every `search_jobs` row already carries -- the follow-up call\n    for a role you hold an identifier for, instead of re-pulling the whole\n    company with `get_open_reqs`. Scoped exactly as `search_jobs` is:\n    ATS-only and freshness-floored. The body adds `raw_title` (the\n    posting's own title) and `boards`, the full deduped list of boards\n    reporting this req. A role that does not exist, is closed, or has not\n    reached the freshness floor is an explicit error, never an empty\n    success -- and it is not billed. No key yet? On the hosted HTTP\n    endpoint the first calls are free: send no `X-API-Key` header and\n    the lookup runs on a shared demo credential, billed to\n    nobody and marked as such, until a per-IP limit is reached.","description_after":"One open role's detail, addressed by the `company_id` + `req_key`\n    pair every `search_jobs` row already carries -- the follow-up call\n    for a role you hold an identifier for, instead of re-pulling the whole\n    company with `get_open_reqs`. Scoped exactly as `search_jobs` is:\n    LinkedIn-excluded (ATS tenants plus public job boards and aggregators) and freshness-floored. The body adds `raw_title` (the\n    posting's own title) and `boards`, the full deduped list of boards\n    reporting this req. A role that does not exist, is closed, or has not\n    reached the freshness floor is an explicit error, never an empty\n    success -- and it is not billed. No key yet? On the hosted HTTP\n    endpoint the first calls are free: send no `X-API-Key` header and\n    the lookup runs on a shared demo credential, billed to\n    nobody and marked as such, until a per-IP limit is reached.","description_similarity":0.925,"before_hash":"a43152db403c1cd868d138e1e4f52c4f","after_hash":"3bc99e869df9f3095cd1057338fc25c9"},{"tool":"search_jobs","kind":"changed","observed_at":"2026-10-06T00:35:21.648Z","fields":["description","inputSchema"],"description_before":"Flat, role-granular job search -- the individual open roles across\n    companies matching `role` (function) / `geo` (country) / `since`, one\n    row per logical req (each with its own `company_id` + `req_key`),\n    ATS-only + freshness-floored. Keyset-paginated via the opaque `cursor`\n    (a prior call's `next_cursor`). Use `who_is_hiring_for` for the\n    company-granular reverse view. `role` must be a function id (as seen\n    in prior results); a plain role name like 'engineering' is rejected\n    with an explicit error rather than an empty result -- pass plain\n    language as `q` instead, which searches the posting's own title,\n    expanded semantically to nearby titles, and reports each row's\n    `relevance` (0-1). `q` is independent of `role`: pass both to search\n    titles within one function. `sort` is 'relevance' (the default with a\n    `q`) or 'recency'; omit both and the page keeps its stable default\n    order. `limit` is bounded: an oversized page is rejected rather than\n    truncated, so page through the full set with `cursor` instead of\n    raising `limit`. No key yet? On the hosted HTTP endpoint the first\n    calls are free: send no `X-API-Key` header and the search\n    runs on a shared demo credential -- a smaller page, billed to nobody,\n    and the result says so -- until a per-IP limit is reached, after which\n    the answer becomes a signup link whose minted key finishes this exact\n    search. On any other transport a blank key answers with that signup\n    link straight away.","description_after":"Flat, role-granular job search -- the individual open roles across\n    companies matching `role` (function) / `geo` (country) / `since`, one\n    row per logical req (each with its own `company_id` + `req_key`),\n    LinkedIn-excluded (ATS tenants plus public job boards and aggregators; each row's `board` names its source) +\n    freshness-floored. `since` filters on `first_seen`, our first\n    observation of the req (not the employer's posting date); each row's\n    `source_posted_at` is the date the source itself published, null when it\n    gave none. Keyset-paginated via the opaque `cursor`\n    (a prior call's `next_cursor`). Use `who_is_hiring_for` for the\n    company-granular reverse view. `role` must be a function id (as seen\n    in prior results); a plain role name like 'engineering' is rejected\n    with an explicit error rather than an empty result -- pass plain\n    language as `q` instead, which searches the posting's own title,\n    expanded semantically to nearby titles, and reports each row's\n    `relevance` (0-1). `q` is independent of `role`: pass both to search\n    titles within one function. `sort` is 'relevance' (the default with a\n    `q`) or 'recency'; omit both and the page keeps its stable default\n    order. `limit` is bounded: an oversized page is rejected rather than\n    truncated, so page through the full set with `cursor` instead of\n    raising `limit`. No key yet? On the hosted HTTP endpoint the first\n    calls are free: send no `X-API-Key` header and the search\n    runs on a shared demo credential -- a smaller page, billed to nobody,\n    and the result says so -- until a per-IP limit is reached, after which\n    the answer becomes a signup link whose minted key finishes this exact\n    search. On any other transport a blank key answers with that signup\n    link straight away.","description_similarity":0.851,"before_hash":"656703cc1a8711004f69d777e86c1ec0","after_hash":"4bff9ce8f88e03d66455996f13ad2299"},{"tool":"who_is_hiring_for","kind":"changed","observed_at":"2026-10-06T00:35:21.648Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"e3a078968fa4ac1eb6ce96aed6224900","after_hash":"ddaa22f2a9c9c0f141ea5e1495a23b02"},{"tool":"get_open_reqs","kind":"changed","observed_at":"2026-10-06T00:35:21.648Z","fields":["description"],"description_before":"The company's current active reqs, deduped across boards --\n    ATS/board-only, freshness-floored. `function` must be a function id\n    (as seen in prior results); a plain role name like 'engineering' is\n    rejected with an explicit error rather than an empty result. `limit`\n    is bounded: an oversized page is rejected rather than truncated.","description_after":"The company's current active reqs, deduped across boards --\n    LinkedIn-excluded: ATS tenants plus public job boards and aggregators; each row's `boards` names its source.\n    Freshness-floored. Each row's `first_seen` is our first observation of\n    the req, not the employer's posting date; `source_posted_at` is the date\n    the source itself published, null when it gave none. `function` must be a function id\n    (as seen in prior results); a plain role name like 'engineering' is\n    rejected with an explicit error rather than an empty result. `limit`\n    is bounded: an oversized page is rejected rather than truncated.","description_similarity":0.56,"before_hash":"ec3fdddc3e16c46ff62f6234db86bbce","after_hash":"6882493537bfe437ba6a7dd652607a2b"},{"tool":"is_hiring","kind":"changed","observed_at":"2026-10-06T00:35:21.648Z","fields":["description"],"description_before":"WHEN an agent already holds a company and needs to qualify it -- the cheap gate before spending a richer call. ATS/board-only and freshness-floored. Takes the integer `company_id` from an earlier result, not a company name or domain. company_id=1234 -> is_hiring true, open_req_count 7, coverage_status \"ats_direct_hit\". company_id=5678 -> is_hiring false with coverage_status \"no_ats_signal\" -- that company has no ATS coverage yet, which is not evidence it is quiet, so do not score it as a negative. No key yet? Pass `plane_api_key` as an empty string and the call answers with a signup link instead of an auth error. To find companies in the first place, use `who_is_hiring_for`.","description_after":"WHEN an agent already holds a company and needs to qualify it -- the cheap gate before spending a richer call. LinkedIn-excluded (ATS tenants plus public job boards and aggregators) and freshness-floored. Takes the integer `company_id` from an earlier result, not a company name or domain. company_id=1234 -> is_hiring true, open_req_count 7, coverage_status \"ats_direct_hit\". company_id=5678 -> is_hiring false with coverage_status \"no_ats_signal\" -- that company has no ATS coverage yet, which is not evidence it is quiet, so do not score it as a negative. No key yet? Pass `plane_api_key` as an empty string and the call answers with a signup link instead of an auth error. To find companies in the first place, use `who_is_hiring_for`.","description_similarity":0.89,"before_hash":"a378efcfe703d8133695c7535dcecd16","after_hash":"7e7115f02daa1769e849b18c8b598129"},{"tool":"write_outcome","kind":"changed","observed_at":"2026-10-02T16:42:55.779Z","fields":["description"],"description_before":"Write back a conversion outcome for `company_id` -- the\n    label-flywheel substrate. Appends to `outcome_labels` scoped to the\n    caller's own customer.\n\n    Plane session only: `outcome_labels` is plane-owned (Phase 1 dropped its\n    one foreign key into the corpus) and this tool reads no corpus table.","description_after":"WHEN a company you reached through a signal converts -- a reply, a\n    meeting, a closed deal -- report it back. Takes the `company_id`, a short\n    `outcome` label of your choosing (e.g. \"meeting_booked\"), the\n    `observed_at` time it happened and, optionally, the `req_key` of the role\n    that prompted the outreach: {\"company_id\": 1234, \"outcome\":\n    \"meeting_booked\", \"observed_at\": \"2026-10-01T09:00:00Z\"} -> {\"id\": 87}.\n    Each call adds one record, visible only to your own account; nothing is\n    overwritten, so report a later stage as a new outcome. Never billed. Needs\n    your key: a blank one returns a signup link.","description_similarity":0.144,"before_hash":"b325606f7c4fbbe4d76146e27d04b508","after_hash":"06022d34aa1a9e68e073deb1d8fc4f12"},{"tool":"cancel_watch","kind":"changed","observed_at":"2026-10-02T16:42:55.779Z","fields":["description"],"description_before":"WHEN a watch should stop firing. Takes the `id` `watch_company`\n    returned (or `list_watches` lists): {\"watch_id\": 42} -> {\"id\": 42,\n    \"canceled\": true}. Idempotent -- cancelling a watch you already cancelled\n    succeeds again. An id that is not one of your watches is an error,\n    identical whether it belongs to someone else or does not exist. Frees the\n    slot a free key's watch limit counts. Never billed. Needs your key: a\n    blank one returns a signup link.\n\n    Plane session only: `watch_subscriptions` is plane-owned.","description_after":"WHEN a watch should stop firing. Takes the `id` `watch_company`\n    returned (or `list_watches` lists): {\"watch_id\": 42} -> {\"id\": 42,\n    \"canceled\": true}. Idempotent -- cancelling a watch you already cancelled\n    succeeds again. An id that is not one of your watches is an error,\n    identical whether it belongs to someone else or does not exist. Frees the\n    slot a free key's watch limit counts. Never billed. Needs your key: a\n    blank one returns a signup link.","description_similarity":0.918,"before_hash":"b71acd54a258102fcec8bbfe1f197835","after_hash":"63bbad2a2ea0cc806f8b83a94d5b7c31"},{"tool":"list_watches","kind":"changed","observed_at":"2026-10-02T16:42:55.779Z","fields":["description"],"description_before":"WHEN you need to see what you are subscribed to -- before adding a\n    watch, or to find the `id` `cancel_watch` takes. Returns your live\n    watches newest first, cancelled ones excluded: {} -> {\"watches\": [{\"id\":\n    ..., \"company_id\": ..., \"event_types\": [...], \"webhook_endpoint_id\": ...,\n    \"status\": \"firing\", ...}]}. Each also reports its heartbeat --\n    `last_fired_at`, `fires_last_7d`, `fires_last_30d`, `fires_last_hour`\n    against `max_fires_per_hour`, `rate_limited`, and a one-word `status` --\n    so a watch silent because nobody is hiring reads differently from one\n    that can never match or whose endpoint is failing. Never billed. Needs\n    your key: a blank one returns a signup link.\n\n    Plane session only: `watch_subscriptions` is plane-owned.","description_after":"WHEN you need to see what you are subscribed to -- before adding a\n    watch, or to find the `id` `cancel_watch` takes. Returns your live\n    watches newest first, cancelled ones excluded: {} -> {\"watches\": [{\"id\":\n    ..., \"company_id\": ..., \"event_types\": [...], \"webhook_endpoint_id\": ...,\n    \"status\": \"firing\", ...}]}. Each also reports its heartbeat --\n    `last_fired_at`, `fires_last_7d`, `fires_last_30d`, `fires_last_hour`\n    against `max_fires_per_hour`, `rate_limited`, and a one-word `status` --\n    so a watch silent because nobody is hiring reads differently from one\n    that can never match or whose endpoint is failing. Never billed. Needs\n    your key: a blank one returns a signup link.","description_similarity":0.938,"before_hash":"a4a5796f8f6ebfe5be9dec18e4169848","after_hash":"2dcebff1c29c7944b62f39d5a98e01e4"},{"tool":"register_webhook","kind":"changed","observed_at":"2026-10-02T16:42:55.779Z","fields":["description"],"description_before":"Register the delivery target a watch fires to, and get back the\n    `webhook_endpoint_id` `watch_company` needs -- call this first if you\n    do not already hold one. Idempotent: registering the same `url` twice\n    returns the same id, so retrying is safe and never leaves you with two\n    endpoints. `secret` is optional; supply one to verify the\n    `X-Plane-Signature` on delivered payloads, omit it and one is\n    generated (it is never returned). Registration itself is free -- the\n    `watch_company` call that follows is what bills.\n\n    Plane session only: `webhook_endpoints` is plane-owned and this tool reads\n    no corpus table.","description_after":"Register the delivery target a watch fires to, and get back the\n    `webhook_endpoint_id` `watch_company` needs -- call this first if you\n    do not already hold one. Idempotent: registering the same `url` twice\n    returns the same id, so retrying is safe and never leaves you with two\n    endpoints. `secret` is optional; supply one to verify the\n    `X-Plane-Signature` on delivered payloads, omit it and one is\n    generated (it is never returned). Registration itself is free -- the\n    `watch_company` call that follows is what bills.","description_similarity":0.886,"before_hash":"2feebb653e88eaf2060c4e1fcfd3da57","after_hash":"3128cd07236dfac8aec8b676a3951f12"}],"next_before":null,"next_actions":[]}