API 참조

Monitoring 감시 생성

POST/v1/watches

계약 v1 / 1.0.0 62 / 2026-10-10

이 페이지에서

기존 Monitoring 프로젝트에 독립적인 규칙으로 주소를 연결합니다. 프로젝트는 Account에서 생성합니다. 하나의 주소를 여러 프로젝트에서 사용할 수 있습니다. 동일한 연결을 반복하는 것은 일반적인 규칙 변경 API가 아니므로 규칙은 Account에서 변경하세요.

키 권한: watches / write / monitoring.

요청 본문

필드유형필수설명
projectstring아니요프로젝트 ID입니다. 프로젝트 한정 키가 아니라면 모니터링 목록 조회나 생성에 필요합니다. 다른 작업에서 생략하면 해당 작업의 계정/프로젝트 맥락을 사용합니다. 명시적으로 지정하세요.
chainstring예GET /v1/chains의 네트워크 코드입니다.
minLength: 1
addressstring예선택한 네트워크의 주소이며 검증 및 정규화됩니다.
minLength: 1
assetstring아니요exact의 기본 자산: native, 지원 심볼 또는 토큰 식별자입니다.
Default: native
labelstring아니요주소록 이름입니다.
maxLength: 60
notestring아니요선택적 주소록 메모입니다.
maxLength: 280
watch_outgoingboolean아니요출금 작업도 받습니다. 해당 네트워크가 이를 지원해야 합니다.
Default: false
asset_policystring아니요exact는 한 자산을, allow는 asset_ids를, all은 네트워크의 모든 자산을 선택합니다. 토큰이 없는 네트워크는 native/exact만 지원합니다.
exact, allow, all; 기본값: exact
asset_idsstring[]아니요exact는 정확히 하나, allow는 하나 이상, all은 빈 목록입니다. exact에서 목록이 비어 있으면 asset을 사용합니다.
maxItems: 100
excluded_asset_idsstring[]아니요제외할 자산입니다.
maxItems: 100
min_confirmationsinteger아니요최소 확인 횟수입니다.
Default: 0; minimum: 0
min_amountstring아니요소수 금액이 아닌 최소 단위의 음이 아닌 임계값입니다.
pattern: ^[0-9]+$
watch_contractsboolean아니요지원되는 계약 이벤트를 받습니다.
기본값: false
watch_unexpected_assetsboolean아니요예상하지 않은 자산 이벤트를 받습니다.
기본값: false
application/json
{
  "project": "1002",
  "chain": "ethereum",
  "address": "0x52908400098527886E0F7030069857D2E4169EE7",
  "asset": "native",
  "label": "Treasury"
}

요청 예시

예제는 귀하의 계정에서 실제 작업을 수행합니다. 코드에 명시된 환경 변수를 설정하세요. 키를 비공개로 유지하세요. 쓰기 요청은 자동 재시도하지 않습니다.

Shell / cURL
#!/usr/bin/env bash
set -euo pipefail
: "${CRYPTANIO_API_KEY:?Set CRYPTANIO_API_KEY}"
: "${CRYPTANIO_PROJECT_ID:?Set CRYPTANIO_PROJECT_ID}"
json_string() {
  local text="$1" char code index output='"'
  for ((index=0; index<${#text}; index++)); do
    char="${text:index:1}"
    case "$char" in
      '"'|'\') output+="\\$char" ;;
      *) printf -v code '%d' "'$char"
         if ((code < 32)); then printf -v char '\\u%04x' "$code"; fi
         output+="$char" ;;
    esac
  done
  printf '%s"' "$output"
}
response_file="$(mktemp)"
trap 'rm -f "$response_file"' EXIT
transfer_status=0
http_status="$(curl \
  --silent --show-error --max-time 30 --request POST \
  --header "Authorization: Bearer $CRYPTANIO_API_KEY" \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data-binary '{"project":'"$(json_string "$CRYPTANIO_PROJECT_ID")"',"chain":"ethereum","address":"0x52908400098527886E0F7030069857D2E4169EE7","asset":"native","label":"Treasury"}' \
  "https://api.cryptanio.com/v1/watches" \
  --output "$response_file" --write-out '%{http_code}')" || transfer_status=$?
if [[ "$http_status" == 2?? ]]; then
  cat "$response_file"
  exit "$transfer_status"
fi
printf 'HTTP %s\n' "$http_status" >&2
cat "$response_file" >&2
exit 1
예제 다운로드
Go
// Go; standard library only. Run: go run request.go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "net/url"
    "os"
    "time"
)

func env(name string) string {
    value := os.Getenv(name)
    if value == "" { fmt.Fprintln(os.Stderr, "Set", name); os.Exit(1) }
    return value
}
func run() error {
    path := "/v1/watches"

    endpoint, err := url.Parse("https://api.cryptanio.com" + path)
    if err != nil { return err }
    query := endpoint.Query()

    endpoint.RawQuery = query.Encode()
    var payload map[string]any
    if err := json.Unmarshal([]byte("{\"project\":\"1002\",\"chain\":\"ethereum\",\"address\":\"0x52908400098527886E0F7030069857D2E4169EE7\",\"asset\":\"native\",\"label\":\"Treasury\"}"), &payload); err != nil { return err }
    payload["project"] = env("CRYPTANIO_PROJECT_ID")
    body, err := json.Marshal(payload)
    if err != nil { return err }
    request, err := http.NewRequest("POST", endpoint.String(), bytes.NewReader(body))
    if err != nil { return err }
    request.Header.Set("Authorization", "Bearer " + env("CRYPTANIO_API_KEY"))
    request.Header.Set("Accept", "application/json")
    request.Header.Set("Content-Type", "application/json")
    client := &http.Client{Timeout: 30 * time.Second, CheckRedirect: func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse }}
    response, err := client.Do(request)
    if err != nil { return err }
    defer response.Body.Close()
    if response.StatusCode < 200 || response.StatusCode >= 300 {
        body, err := io.ReadAll(response.Body)
        if err != nil { return err }
        return fmt.Errorf("HTTP %d: %s", response.StatusCode, body)
    }
    _, err = io.Copy(os.Stdout, response.Body)
    return err
}
func main() {
    if err := run(); err != nil { fmt.Fprintln(os.Stderr, err); os.Exit(1) }
}
예제 다운로드
Rust
// Cargo.toml dependencies:
// reqwest = { version = "=0.12.24", features = ["blocking", "json"] }
// serde_json = "=1.0.145"
use std::{error::Error, io, time::Duration};
use reqwest::{blocking::Client, redirect::Policy, Method, Url};

fn env(name: &str) -> Result<String, Box<dyn Error>> {
    let value = std::env::var(name)?;
    if value.is_empty() { return Err(format!("Set {name}").into()); }
    Ok(value)
}
fn run() -> Result<(), Box<dyn Error>> {
    let mut url = Url::parse("https://api.cryptanio.com")?;
    {
        let mut segments = url.path_segments_mut().map_err(|_| "Invalid base URL")?;
        segments.clear();
        segments.push("v1");
        segments.push("watches");
    }
    let client = Client::builder().timeout(Duration::from_secs(30)).redirect(Policy::none()).build()?;
    let request = client.request(Method::POST, url)
        .header("Authorization", format!("Bearer {}", env("CRYPTANIO_API_KEY")?))
        .header("Accept", "application/json".to_owned())
        .header("Content-Type", "application/json".to_owned());
    let mut body: serde_json::Value = serde_json::from_str("{\"project\":\"1002\",\"chain\":\"ethereum\",\"address\":\"0x52908400098527886E0F7030069857D2E4169EE7\",\"asset\":\"native\",\"label\":\"Treasury\"}")?;
    body["project"] = serde_json::Value::String(env("CRYPTANIO_PROJECT_ID")?);
    let request = request.json(&body);
    let mut response = request.send()?;
    let status = response.status();
    if !status.is_success() { return Err(format!("HTTP {}: {}", status.as_u16(), response.text()?).into()); }
    io::copy(&mut response, &mut io::stdout())?;
    Ok(())
}
fn main() {
    if let Err(error) = run() { eprintln!("{error}"); std::process::exit(1); }
}
예제 다운로드
PHP
<?php
// PHP 8 with the cURL extension. Run this on your server.
function env(string $name): string {
    $value = getenv($name);
    if ($value === false || $value === '') throw new RuntimeException('Set ' . $name);
    return $value;
}
try {
    $path = '/v1/watches';

    $query = [

    ];
    $url = 'https://api.cryptanio.com' . $path . ($query ? '?' . http_build_query($query, '', '&', PHP_QUERY_RFC3986) : '');
    $headers = [
        'Authorization: ' . 'Bearer ' . env('CRYPTANIO_API_KEY'),
        'Accept: ' . 'application/json',
        'Content-Type: ' . 'application/json',
    ];
    $body = json_decode('{"project":"1002","chain":"ethereum","address":"0x52908400098527886E0F7030069857D2E4169EE7","asset":"native","label":"Treasury"}', true, 512, JSON_THROW_ON_ERROR);
    $body['project'] = env('CRYPTANIO_PROJECT_ID');
    $curl = curl_init($url);
    curl_setopt_array($curl, [
        CURLOPT_CUSTOMREQUEST => 'POST',
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => false,
        CURLOPT_CONNECTTIMEOUT => 10,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_POSTFIELDS => json_encode($body, JSON_THROW_ON_ERROR),
    ]);
    $response = curl_exec($curl);
    if ($response === false) throw new RuntimeException(curl_error($curl));
    $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    if ($status < 200 || $status >= 300) throw new RuntimeException('HTTP ' . $status . ': ' . $response);
    echo $response;
} catch (Throwable $error) {
    fwrite(STDERR, $error->getMessage() . PHP_EOL);
    exit(1);
}
예제 다운로드
Python
# Python 3; standard library only.
import json
import os
import sys
from urllib.error import HTTPError, URLError
from urllib.parse import quote, urlencode
from urllib.request import HTTPRedirectHandler, Request, build_opener

def env(name):
    result = os.environ.get(name)
    if not result:
        raise ValueError("Set " + name)
    return result

class NoRedirect(HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, headers, newurl):
        return None

try:
    path = "/v1/watches"

    query = {

    }
    url = "https://api.cryptanio.com" + path + ("?" + urlencode(query) if query else "")
    headers = {
        "Authorization": "Bearer " + env("CRYPTANIO_API_KEY"),
        "Accept": "application/json",
        "Content-Type": "application/json",
    }
    body = json.loads("{\"project\":\"1002\",\"chain\":\"ethereum\",\"address\":\"0x52908400098527886E0F7030069857D2E4169EE7\",\"asset\":\"native\",\"label\":\"Treasury\"}")
    body["project"] = env("CRYPTANIO_PROJECT_ID")
    data = json.dumps(body).encode("utf-8")
    request = Request(url, data=data, headers=headers, method="POST")
    with build_opener(NoRedirect()).open(request, timeout=30) as response:
        if not 200 <= response.status < 300:
            raise ValueError("HTTP " + str(response.status))
        sys.stdout.buffer.write(response.read())
except HTTPError as error:
    print("HTTP " + str(error.code) + ": " + error.read().decode("utf-8", errors="replace"), file=sys.stderr)
    sys.exit(1)
except (ValueError, URLError, OSError) as error:
    print(str(error), file=sys.stderr)
    sys.exit(1)
예제 다운로드
Node.js
// Node.js 18+. Run on your server, never in a browser.
const env = name => {
  const result = process.env[name];
  if (!result) throw new Error(`Set ${name}`);
  return result;
};
try {
  let path = "/v1/watches";

  const url = new URL(path, "https://api.cryptanio.com");

  const headers = {
    "Authorization": "Bearer " + env("CRYPTANIO_API_KEY"),
    "Accept": "application/json",
    "Content-Type": "application/json",
  };
  const body = {
    "project": "1002",
    "chain": "ethereum",
    "address": "0x52908400098527886E0F7030069857D2E4169EE7",
    "asset": "native",
    "label": "Treasury"
  };
  body["project"] = env("CRYPTANIO_PROJECT_ID");
  const response = await fetch(url, {
    method: "POST", headers, redirect: "manual",
    signal: AbortSignal.timeout(30_000), body: JSON.stringify(body),
  });
  if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
  if (response.body) {
    for await (const chunk of response.body) process.stdout.write(chunk);
  }
} catch (error) {
  console.error(error.message);
  process.exitCode = 1;
}
예제 다운로드

응답 및 오류

201 성공 응답.
필드유형필수설명
idstring예불투명 식별자입니다. 문자열로 유지하세요.
minLength: 1
project_idstring예불투명 식별자입니다. 문자열로 유지하세요.
minLength: 1
servicestring예프로젝트 서비스입니다.
monitoring
book_address_idstring예일치하는 주소록 주소 ID입니다.
minLength: 1
statusstring예프로젝트와 주소의 연결 상태입니다.
active, paused, deleted
chainstring예네트워크 코드입니다.
addressstring예정규화된 주소입니다.
assetstring예응답 문자열에 포함할 자산입니다. 여러 자산은 쉼표로 구분합니다.
metaobject아니요설정된 경우 주소 이름과 메모입니다.
watched_asstring아니요네트워크에서 사용하는 추가 주소 식별자입니다.
sandboxboolean아니요테스트 모니터링이면 true이며 생략하면 false입니다.
watch_outgoingboolean예출금 작업을 모니터링하는지 여부입니다.
origin_kindsstring[]예프로젝트에 주소를 추가한 방법입니다.
created_atstring예RFC 3339 형식의 UTC 날짜 및 시간입니다.
date-time
201 application/json
{
  "id": "1008",
  "project_id": "1002",
  "service": "monitoring",
  "book_address_id": "1007",
  "status": "active",
  "chain": "ethereum",
  "address": "0x52908400098527886E0F7030069857D2E4169EE7",
  "asset": "native",
  "sandbox": true,
  "watch_outgoing": false,
  "origin_kinds": [
    "manual"
  ],
  "created_at": "2026-10-06T10:00:00Z"
}
400 잘못된 요청(bad_request, unsupported_asset).
필드유형필수설명
errorobject예
400 application/json
{
  "error": {
    "code": "forbidden",
    "message": "this API key is read-only"
  }
}
401 유효한 활성 API 키가 없습니다(unauthorized).
필드유형필수설명
errorobject예
401 application/json
{
  "error": {
    "code": "forbidden",
    "message": "this API key is read-only"
  }
}
402 리소스 한도에 도달했습니다(limit_reached).
필드유형필수설명
errorobject예
402 application/json
{
  "error": {
    "code": "forbidden",
    "message": "this API key is read-only"
  }
}
403 키가 작업, 프로젝트, 서비스 또는 IP를 허용하지 않거나 이메일이 확인되지 않았습니다.
필드유형필수설명
errorobject예
403 application/json
{
  "error": {
    "code": "forbidden",
    "message": "this API key is read-only"
  }
}
409 상태 충돌, 재시도 매개변수 충돌 또는 결제 리소스 한도(conflict, limit_reached, service_inactive).
필드유형필수설명
errorobject예
409 application/json
{
  "error": {
    "code": "forbidden",
    "message": "this API key is read-only"
  }
}
429 요청이 너무 많습니다(rate_limited). Retry-After 이후 재시도하세요.
필드유형필수설명
errorobject예
429 application/json
{
  "error": {
    "code": "forbidden",
    "message": "this API key is read-only"
  }
}
500 내부 오류(internal).
필드유형필수설명
errorobject예
500 application/json
{
  "error": {
    "code": "forbidden",
    "message": "this API key is read-only"
  }
}
503 일시적 사용 불가(unavailable). 점진적 대기로 재시도하세요.
필드유형필수설명
errorobject예
503 application/json
{
  "error": {
    "code": "forbidden",
    "message": "this API key is read-only"
  }
}

오류 처리 및 안전한 재시도

중첩 객체

Watch

필드유형필수설명
idstring예불투명 식별자입니다. 문자열로 유지하세요.
minLength: 1
project_idstring예불투명 식별자입니다. 문자열로 유지하세요.
minLength: 1
servicestring예프로젝트 서비스입니다.
monitoring
book_address_idstring예일치하는 주소록 주소 ID입니다.
minLength: 1
statusstring예프로젝트와 주소의 연결 상태입니다.
active, paused, deleted
chainstring예네트워크 코드입니다.
addressstring예정규화된 주소입니다.
assetstring예응답 문자열에 포함할 자산입니다. 여러 자산은 쉼표로 구분합니다.
metaobject아니요설정된 경우 주소 이름과 메모입니다.
watched_asstring아니요네트워크에서 사용하는 추가 주소 식별자입니다.
sandboxboolean아니요테스트 모니터링이면 true이며 생략하면 false입니다.
watch_outgoingboolean예출금 작업을 모니터링하는지 여부입니다.
origin_kindsstring[]예프로젝트에 주소를 추가한 방법입니다.
created_atstring예RFC 3339 형식의 UTC 날짜 및 시간입니다.
date-time
ID

불투명 식별자입니다. 형식은 보장되지 않으므로 숫자로 변환하지 마세요.

string 불투명 식별자입니다. 형식은 보장되지 않으며 숫자로 변환하지 마세요.

StringMap

object

WatchRequest

필드유형필수설명
projectstring아니요프로젝트 ID입니다. 프로젝트 한정 키가 아니라면 모니터링 목록 조회나 생성에 필요합니다. 다른 작업에서 생략하면 해당 작업의 계정/프로젝트 맥락을 사용합니다. 명시적으로 지정하세요.
chainstring예GET /v1/chains의 네트워크 코드입니다.
minLength: 1
addressstring예선택한 네트워크의 주소이며 검증 및 정규화됩니다.
minLength: 1
assetstring아니요exact의 기본 자산: native, 지원 심볼 또는 토큰 식별자입니다.
Default: native
labelstring아니요주소록 이름입니다.
maxLength: 60
notestring아니요선택적 주소록 메모입니다.
maxLength: 280
watch_outgoingboolean아니요출금 작업도 받습니다. 해당 네트워크가 이를 지원해야 합니다.
Default: false
asset_policystring아니요exact는 한 자산을, allow는 asset_ids를, all은 네트워크의 모든 자산을 선택합니다. 토큰이 없는 네트워크는 native/exact만 지원합니다.
exact, allow, all; 기본값: exact
asset_idsstring[]아니요exact는 정확히 하나, allow는 하나 이상, all은 빈 목록입니다. exact에서 목록이 비어 있으면 asset을 사용합니다.
maxItems: 100
excluded_asset_idsstring[]아니요제외할 자산입니다.
maxItems: 100
min_confirmationsinteger아니요최소 확인 횟수입니다.
Default: 0; minimum: 0
min_amountstring아니요소수 금액이 아닌 최소 단위의 음이 아닌 임계값입니다.
pattern: ^[0-9]+$
watch_contractsboolean아니요지원되는 계약 이벤트를 받습니다.
기본값: false
watch_unexpected_assetsboolean아니요예상하지 않은 자산 이벤트를 받습니다.
기본값: false
RawAmount

string

Error

필드유형필수설명
errorobject예