/v1/account/monitors
account/monitors
Monitoring: 회사 모니터링 설정, 생성, 일시 중지, 삭제.
모니터가 회사를 대신 지켜봐요. 정해진 간격으로 새 Signal을 확인하고, 새 Signal은 각각 웹훅으로 웹훅 엔드포인트에 보내요.
비용과 한도
| 항목 | 크레딧 |
|---|---|
| 매일 확인하는 모니터, 30일 기준 | 50 |
| 3일마다 확인하는 모니터, 30일 기준 | 40 |
| 7일마다 확인하는 모니터, 30일 기준 | 20 |
| 30일마다 확인하는 모니터, 30일 기준 | 10 |
| 기간 내 추가로 성공한 확인 1회당 | +2 |
한도: 분당 30 요청. 생성, 수정, 삭제: 분당 10.
모니터 생성과 첫 기준선은 무료예요. 30일 주기는 모니터가 활성화되는 즉시 과금돼요. 가격은 확인 간격에 따라 다르며, 한 주기 안에서 그 간격으로 예정된 모든 확인을 포함해요.
두 단계 사이의 간격은 바로 다음으로 더 잦은 단계와 같은 비용이 들어요: 4일마다는 3일마다와 같은 비용이에요.
추가 확인은 주로 주기 중간에 간격을 줄일 때 생겨요. 성공한 추가 확인은 각각 표에 나온 금액이 들어요.
30일이 지나면 주기는 그때 유효한 가격으로 자동 갱신돼요. 실패한 확인은 비용이 들지 않아요. 일시 중지, 보관, 간격 변경 시에는 환불하지 않아요.
계정마다 최대 50개의 모니터를 동시에 가질 수 있고, 회사당 하나예요. 24시간 안에 최대 50개의 모니터를 만들 수 있으며, 보관된 것도 포함돼요.
간격별 가격은 GET /v1/account/monitoring/pricing으로 무료로 확인해요. 여기서는 7일마다 확인하는 경우예요:
curl -G "https://handelsregister.ai/api/v1/account/monitoring/pricing" \ -H "x-api-key: YOUR_API_KEY" \ --data-urlencode 'poll_interval_days=7'
import requests response = requests.get( "https://handelsregister.ai/api/v1/account/monitoring/pricing", headers={"x-api-key": "YOUR_API_KEY"}, params={ "poll_interval_days": "7", }, ) data = response.json()
const url = new URL("https://handelsregister.ai/api/v1/account/monitoring/pricing"); url.searchParams.append("poll_interval_days", "7"); const response = await fetch(url, { headers: { "x-api-key": "YOUR_API_KEY" }, }); const data = await response.json();
1{2 "pricing": {3 "policy_version": "2026-08.v2",4 "credits_per_run": 2,5 "cycle_minimum_credits": 20,6 "included_runs": 5,7 "cycle_days": 30,8 "estimated_runs": 5,9 "estimated_credits": 2010 },11 "entitled": true,12 "meta": {13 "request_credit_cost": 0,14 "credits_remaining": 14515 }16}
모니터의 작동 방식
- 생성. 회사, 확인 간격, 인증된 웹훅 엔드포인트를 하나 이상 지정해요. 모니터는 상태
initializing으로 시작해요. - 기준선. 최근 며칠의 Signal을 알려진 것으로 기록해요. 전달되지 않으므로, 그 이후의 새 Signal만 받아요.
- 활성화. 주기를 과금하고, 모니터가
active가 되어 바로 첫 확인을 해요. - 확인. 그 뒤로는 정한 간격으로 확인해요. 새 Signal마다 모니터당 메시지 하나가 웹훅 엔드포인트로 가요.
- 갱신. 각 주기가 끝나면 잔액이 충분한 한 다음 주기가 자동으로 과금돼요.
확인 간격은 1~30일이에요. 확인 시각은 한 시간 안에서 달라질 수 있어요. 각 확인은 며칠 전까지 거슬러 보므로 늦게 공고된 등기도 도착해요.
모니터는 플랜의 Signals 주제를 전달해요: 모든 계정에 다섯 가지, Pro에 파산, Max에 조직 변경 & M&A. 웹훅은 signals와 같은 Signal을 필드 data.signal에 담아요.
| 상태 | 의미 |
|---|---|
| initializing | 생성됨; 기준선과 활성화가 진행 중이에요. |
| active | 정한 간격으로 확인해요. |
| paused_user | 내가 일시 중지했어요. |
| paused_configuration | 활성 상태의 인증된 웹훅 엔드포인트가 더 이상 연결되어 있지 않아요. |
| paused_billing | 잔액이 주기나 추가 확인 비용을 감당하지 못해요. 또는 가격이 바뀌어 동의를 기다리고 있어요. |
| error | 여러 번 연속으로 확인에 실패했어요. |
| archived | 완전히 종료됨. ID로 모니터를 계속 읽을 수 있지만 목록에는 더 이상 나오지 않아요. |
일시 중지된 모니터와 오류에는 status_reason이 이유를 설명해요. 예: no_verified_endpoint 또는 insufficient_cycle_floor.
엔드포인트
모든 경로는 /v1/account 아래에 있어요. 헤더 x-api-key의 API 키로 읽고 써요.
| 메서드 | 경로 | 용도 |
|---|---|---|
| GET |
/v1/account/monitors |
보관된 것을 제외한 모든 모니터, 최신순. |
| POST |
/v1/account/monitors |
모니터 생성. |
| GET |
/v1/account/monitors/{id} |
주기와 최근 확인이 담긴 모니터 하나. |
| PATCH |
/v1/account/monitors/{id} |
확인 간격 변경. |
| POST |
/v1/account/monitors/{id}/pause |
일시 중지. |
| POST |
/v1/account/monitors/{id}/resume |
재개. |
| DELETE |
/v1/account/monitors/{id} |
보관. |
| GET |
/v1/account/monitoring/pricing |
간격별 가격. |
Idempotency-Key
모든 쓰기 요청에는 헤더 Idempotency-Key가 필요해요. 작업마다 고유한 값이며, UUID가 가장 좋아요. 없으면 API가 428로 응답해요.
24시간 안에 같은 키와 같은 데이터로 요청을 반복하면 저장된 응답을 다시 받아요. 이 응답에는 헤더 Idempotency-Status: replayed가 붙어요. 그래서 네트워크 오류로 두 번째 모니터가 생기지 않아요.
오류 응답에도 적용돼요. 그러니 수정한 뒤 새로 시도할 때는 새 키를 쓰세요. 같은 키를 다른 데이터로 쓰면 409가 반환돼요.
최대 128자이며 문자, 숫자, . _ : -를 쓸 수 있어요. 첫 글자는 문자나 숫자예요. 다른 형식의 키는 400을 반환해요.
모니터 생성
회사의 entity_id와 인증된 웹훅 엔드포인트가 하나 이상 필요해요. account/webhook-endpoints를 참고하세요.
curl -X POST "https://handelsregister.ai/api/v1/account/monitors" \ -H "x-api-key: YOUR_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "entity_id": "94eb910fef13f94585c48c263fa446d4", "label": "Hetzner Online GmbH", "poll_interval_days": 7, "endpoint_ids": [ "wep_01m6b3j1g0cdz98hw8zdefbf52" ] }'
import uuid import requests response = requests.post( "https://handelsregister.ai/api/v1/account/monitors", headers={ "x-api-key": "YOUR_API_KEY", "Idempotency-Key": str(uuid.uuid4()), }, json={ "entity_id": "94eb910fef13f94585c48c263fa446d4", "label": "Hetzner Online GmbH", "poll_interval_days": 7, "endpoint_ids": [ "wep_01m6b3j1g0cdz98hw8zdefbf52" ] }, ) data = response.json()
const response = await fetch("https://handelsregister.ai/api/v1/account/monitors", { method: "POST", headers: { "x-api-key": "YOUR_API_KEY", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "entity_id": "94eb910fef13f94585c48c263fa446d4", "label": "Hetzner Online GmbH", "poll_interval_days": 7, "endpoint_ids": [ "wep_01m6b3j1g0cdz98hw8zdefbf52" ] }), }); const data = await response.json();
| 이름 | 타입 | 설명 | 예시 |
|---|---|---|---|
| Idempotency-KeyHeader | 문자열필수 | 작업마다 고유한 값, UUID가 가장 좋아요. Idempotency-Key를 참고하세요.제한: 1~128자 |
req-20260802-01 |
| entity_idBody | 문자열필수 |
fetch-organization이나 search-organizations에서 받은 회사의 entity_id.제한: 1~128자 |
94eb910fef13f94585c48c263fa446d4 |
| labelBody | 문자열선택 | 모니터 이름.제한: 최대 200자 |
Hetzner Online GmbH |
| poll_interval_daysBody | 정수필수 | 일 단위 확인 간격.제한: 1~30 |
7 |
| endpoint_idsBody | string 목록필수 |
웹훅 엔드포인트의 ID(wep_…). 각각 활성 상태이고 인증되어 있어야 해요.제한: 1~10개 항목 |
["wep_01m6b3j1g0cdz98hw8zdefbf52"] |
API는 202로 응답해요: 모니터가 생성되고, 기준선과 활성화는 백그라운드에서 진행돼요. meta.billing.charged_credits가 이 단계에서 과금된 것이 없음을 보여 줘요.
1{2 "monitor": {3 "id": "mon_01m6b3m7945dn7cyvexzv41kjz",4 "type": "organization.signals",5 "entity_id": "94eb910fef13f94585c48c263fa446d4",6 "label": "Hetzner Online GmbH",7 "poll_interval_days": 7,8 "status": "initializing",9 "status_reason": null,10 "pricing_policy_version": "2026-08.v2",11 "baseline_completed_at": null,12 "activated_at": null,13 "last_succeeded_at": null,14 "next_poll_at": null,15 "created_at": "2026-11-01T08:29:13+00:00"16 },17 "meta": {18 "message": "Monitor created; the free baseline is queued and this request charged 0 credits. The cycle price is charged only when activation succeeds.",19 "baseline_queued": true,20 "billing": {21 "charged_credits": 0,22 "new_cycle": false,23 "floor_transaction_id": null24 },25 "request_credit_cost": 0,26 "credits_remaining": 14527 }28}
모니터 목록과 수정
GET /v1/account/monitors는 최대 100개의 모니터를 total과 함께 monitors 아래에 반환해요. 보관된 것은 목록에 없어요.
GET /v1/account/monitors/{id}는 billing_cycle에 현재 주기를, recent_runs에 최근 확인도 보여 줘요.
curl -G "https://handelsregister.ai/api/v1/account/monitors/mon_01m65pn3vm11sjjp1j076cbvec" \ -H "x-api-key: YOUR_API_KEY"
import requests response = requests.get( "https://handelsregister.ai/api/v1/account/monitors/mon_01m65pn3vm11sjjp1j076cbvec", headers={"x-api-key": "YOUR_API_KEY"}, ) data = response.json()
const url = new URL("https://handelsregister.ai/api/v1/account/monitors/mon_01m65pn3vm11sjjp1j076cbvec"); const response = await fetch(url, { headers: { "x-api-key": "YOUR_API_KEY" }, }); const data = await response.json();
1{2 "monitor": {3 "id": "mon_01m65pn3vm11sjjp1j076cbvec",4 "type": "organization.signals",5 "entity_id": "94eb910fef13f94585c48c263fa446d4",6 "label": "Hetzner Online GmbH",7 "poll_interval_days": 1,8 "status": "active",9 "status_reason": null,10 "pricing_policy_version": "2026-08.v2",11 "baseline_completed_at": "2026-10-30T06:06:28+00:00",12 "activated_at": "2026-10-30T06:06:28+00:00",13 "last_succeeded_at": "2026-10-30T06:06:53+00:00",14 "next_poll_at": "2026-10-31T06:19:12+00:00",15 "created_at": "2026-10-30T06:06:18+00:00"16 },17 "billing_cycle": {18 "starts_at": "2026-10-30T06:06:28+00:00",19 "ends_at": "2026-11-29T06:06:28+00:00",20 "floor_credits": 50,21 "credits_per_run": 2,22 "included_runs": 30,23 "successful_runs": 1,24 "extra_credits_settled": 0,25 "pricing_policy_version": "2026-08.v2"26 },27 "recent_runs": [28 {29 "due_slot_at": "2026-10-30T06:06:28+00:00",30 "kind": "activation_catchup",31 "status": "succeeded",32 "charge_state": "covered",33 "charge_credits": 0,34 "events_new": 0,35 "finished_at": "2026-10-30T06:06:55+00:00"36 }37 ],38 "meta": {39 "request_credit_cost": 0,40 "credits_remaining": 14541 }42}
| 필드 | 의미 |
|---|---|
| id |
모니터 ID, mon_으로 시작해요.
|
| entity_id | 모니터링 대상 회사. |
| poll_interval_days | 일 단위 확인 간격. |
| status, status_reason |
상태, 위 참고. status_reason에 이유가 있어요.
|
| baseline_completed_at, activated_at, last_succeeded_at | 기준선, 활성화, 마지막으로 성공한 확인의 시각. |
| next_poll_at | 다음 예정 확인, 활성 모니터에만. |
| billing_cycle | 현재 주기: 시작, 끝, 가격, 포함된 확인 수, 지금까지 한 확인 수. |
| recent_runs |
결과, 과금, events_new의 새 Signal 수가 담긴 최근 확인.
|
PATCH /v1/account/monitors/{id}는 확인 간격을 바꿔요. 다음 확인은 변경 시점부터 새 간격으로 이어져요.
현재 주기는 가격과 포함된 확인 수를 유지해요. 새 가격은 다음 주기부터 적용돼요. 간격을 줄이면 현재 주기에 추가 확인이 생길 수 있어요.
curl -X PATCH "https://handelsregister.ai/api/v1/account/monitors/mon_01m6b3m7945dn7cyvexzv41kjz" \ -H "x-api-key: YOUR_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "poll_interval_days": 30 }'
import uuid import requests response = requests.patch( "https://handelsregister.ai/api/v1/account/monitors/mon_01m6b3m7945dn7cyvexzv41kjz", headers={ "x-api-key": "YOUR_API_KEY", "Idempotency-Key": str(uuid.uuid4()), }, json={ "poll_interval_days": 30 }, ) data = response.json()
const response = await fetch("https://handelsregister.ai/api/v1/account/monitors/mon_01m6b3m7945dn7cyvexzv41kjz", { method: "PATCH", headers: { "x-api-key": "YOUR_API_KEY", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "poll_interval_days": 30 }), }); const data = await response.json();
1{2 "monitor": {3 "id": "mon_01m6b3m7945dn7cyvexzv41kjz",4 "type": "organization.signals",5 "entity_id": "94eb910fef13f94585c48c263fa446d4",6 "label": "Hetzner Online GmbH",7 "poll_interval_days": 30,8 "status": "initializing",9 "status_reason": null,10 "pricing_policy_version": "2026-08.v2",11 "baseline_completed_at": null,12 "activated_at": null,13 "last_succeeded_at": null,14 "next_poll_at": null,15 "created_at": "2026-11-01T08:29:13+00:00"16 },17 "meta": {18 "request_credit_cost": 0,19 "credits_remaining": 14520 }21}
일시 중지, 재개, 보관
POST …/{id}/pause는 활성 모니터를 멈춰요. 지불한 주기는 끝까지 이어지고, 환불은 없어요.
POST …/{id}/resume은 일시 중지되었거나 오류가 난 모니터를 재개해요. 웹훅 엔드포인트, 잔액, 가격을 다시 확인해요.
지불한 현재 주기 안에서는 재개 비용이 들지 않아요. 주기가 끝났다면 지금 현재 가격으로 새 주기가 시작돼요. 금액은 meta.request_credit_cost에 나와요.
예를 들어 인증된 웹훅 엔드포인트가 없으면 API는 그래도 200으로 응답하지만 meta.activated: false를 줘요. 이유는 모니터의 상태와 status_reason에 있어요.
가격이 바뀌면 활성 모니터는 주기가 끝날 때 pricing_consent_required로 멈춰요. resume으로 새 가격에 동의해요.
DELETE …/{id}는 모니터를 완전히 보관해요. 되돌릴 수 없고 환불도 없어요.
curl -X POST "https://handelsregister.ai/api/v1/account/monitors/mon_01m6b3m7945dn7cyvexzv41kjz/resume" \ -H "x-api-key: YOUR_API_KEY" \ -H "Idempotency-Key: $(uuidgen)"
import uuid import requests response = requests.post( "https://handelsregister.ai/api/v1/account/monitors/mon_01m6b3m7945dn7cyvexzv41kjz/resume", headers={ "x-api-key": "YOUR_API_KEY", "Idempotency-Key": str(uuid.uuid4()), }, ) data = response.json()
const response = await fetch("https://handelsregister.ai/api/v1/account/monitors/mon_01m6b3m7945dn7cyvexzv41kjz/resume", { method: "POST", headers: { "x-api-key": "YOUR_API_KEY", "Idempotency-Key": crypto.randomUUID(), }, }); const data = await response.json();
paused_configuration으로 멈춰요. 웹훅 엔드포인트를 다시 활성화한 뒤 resume으로 모니터를 재개하세요.
오류
오류는 {"error": "…", "meta": {"message": "…"}} 구조예요. 프로그램에서는 error 값을 확인하세요. meta.message의 텍스트는 영어이고 바뀔 수 있어요. 오류는 비용이 들지 않아요.
| 상태 | 원인 | 해결 방법 |
|---|---|---|
| 400 |
URL에 api_key가 있어요. |
키를 헤더 x-api-key로 보내세요. |
| 400 |
Idempotency-Key의 형식이 유효하지 않아요. |
형식을 고치세요. 예: UUID를 쓰세요. |
| 401 | API 키나 토큰이 없거나 유효하지 않아요. |
키를 헤더 x-api-key로 보내세요. |
| 403 |
Bearer 토큰에 account:read 권한이 없어요. |
API 키나 account:read가 있는 토큰을 쓰세요. |
| 403 | 계정의 이메일 주소가 아직 인증되지 않았거나 계정이 잠겼어요. | 인증 이메일의 링크를 여세요. 계정이 잠겼다면 지원팀이 도와드려요. |
| 403 |
Bearer 토큰에 monitoring:manage 권한이 없어요. |
API 키나 관리자 토큰을 쓰세요. |
| 404 | 계정에 이 ID의 모니터가 없어요. | ID를 확인하세요. |
| 409 |
이 회사의 모니터가 이미 있어요(duplicate_monitor). |
기존 모니터를 쓰거나 먼저 보관하세요. |
| 409 |
Idempotency-Key가 이미 다른 데이터로 쓰였거나, 24시간보다 오래되었거나, 아직 처리 중이에요. |
새 키를 쓰거나 잠시 기다리세요. |
| 422 |
값이 유효하지 않아요: invalid_subject, invalid_interval, endpoint_required, monitor_limit 또는 not_resumable. |
값을 고치세요. |
| 428 |
헤더 Idempotency-Key가 없어요. |
헤더를 보내세요. |
| 429 | 요청이 너무 많아요. |
Retry-After 이후에 다시 시도하세요. |
| 429 |
creation_rate_limited: 24시간 안에 새 모니터가 너무 많아요. |
Retry-After 이후에 다시 시도하세요. |
| 503 | Monitoring을 일시적으로 쓸 수 없어요. | 조금 뒤에 다시 시도하세요. |
1{2 "error": "duplicate_monitor",3 "meta": {4 "message": "You already have a monitor for this company.",5 "request_credit_cost": 0,6 "credits_remaining": 1457 }8}