API 참조

이벤트 스트리밍

GET/v1/stream

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

이 페이지에서

event:payment, JSON data 및 주기적 연결 확인 주석을 사용하는 SSE입니다. webhook v1과 형식이 다릅니다. 누락 이벤트는 /events로 복구하세요. Last-Event-ID 재생은 구현되지 않았습니다. 브라우저 기본 EventSource는 Bearer 헤더를 설정할 수 없으므로 서버 클라이언트나 fetch 스트리밍을 사용하고, 쿼리에 키를 넣지 마세요.

키 권한: stream / read.

요청 예시

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

Shell / cURL
#!/usr/bin/env bash
set -euo pipefail
: "${CRYPTANIO_API_KEY:?Set CRYPTANIO_API_KEY}"
# A live SSE connection is deliberately limited to 30 seconds.
exec 3>&1
transfer_status=0
http_status="$(curl \
  --silent --show-error --no-buffer --max-time 30 --request GET \
  --header "Authorization: Bearer $CRYPTANIO_API_KEY" \
  --header 'Accept: text/event-stream' \
  "https://api.cryptanio.com/v1/stream" \
  --output /dev/fd/3 --write-out '%{http_code}')" || transfer_status=$?
exec 3>&-
if [[ "$http_status" == 2?? ]]; then
  exit "$transfer_status"
fi
printf 'HTTP %s\n' "$http_status" >&2
exit 1
예제 다운로드
Go
// Go; standard library only. Run: go run request.go
package main

import (
    "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/stream"

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

    endpoint.RawQuery = query.Encode()

    request, err := http.NewRequest("GET", endpoint.String(), nil)
    if err != nil { return err }
    request.Header.Set("Authorization", "Bearer " + env("CRYPTANIO_API_KEY"))
    request.Header.Set("Accept", "text/event-stream")
    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("stream");
    }
    let client = Client::builder().timeout(Duration::from_secs(30)).redirect(Policy::none()).build()?;
    let request = client.request(Method::GET, url)
        .header("Authorization", format!("Bearer {}", env("CRYPTANIO_API_KEY")?))
        .header("Accept", "text/event-stream".to_owned());
    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/stream';

    $query = [

    ];
    $url = 'https://api.cryptanio.com' . $path . ($query ? '?' . http_build_query($query, '', '&', PHP_QUERY_RFC3986) : '');
    $headers = [
        'Authorization: ' . 'Bearer ' . env('CRYPTANIO_API_KEY'),
        'Accept: ' . 'text/event-stream',
    ];
    $errorBody = '';
    $curl = curl_init($url);
    curl_setopt_array($curl, [
        CURLOPT_CUSTOMREQUEST => 'GET',
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_RETURNTRANSFER => false,
        CURLOPT_FOLLOWLOCATION => false,
        CURLOPT_CONNECTTIMEOUT => 10,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_WRITEFUNCTION => static function ($handle, string $chunk) use (&$errorBody): int {
            $status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
            if ($status >= 200 && $status < 300) { fwrite(STDOUT, $chunk); }
            else { $errorBody .= $chunk; }
            return strlen($chunk);
        },
    ]);
    $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 . ': ' . $errorBody);
} 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/stream"

    query = {

    }
    url = "https://api.cryptanio.com" + path + ("?" + urlencode(query) if query else "")
    headers = {
        "Authorization": "Bearer " + env("CRYPTANIO_API_KEY"),
        "Accept": "text/event-stream",
    }
    data = None
    request = Request(url, data=data, headers=headers, method="GET")
    with build_opener(NoRedirect()).open(request, timeout=30) as response:
        if not 200 <= response.status < 300:
            raise ValueError("HTTP " + str(response.status))
        for line in response:
            sys.stdout.buffer.write(line)
            sys.stdout.buffer.flush()
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/stream";

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

  const headers = {
    "Authorization": "Bearer " + env("CRYPTANIO_API_KEY"),
    "Accept": "text/event-stream",
  };
  const response = await fetch(url, {
    method: "GET", headers, redirect: "manual",
    signal: AbortSignal.timeout(30_000),
  });
  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;
}
예제 다운로드

응답 및 오류

200 Server-Sent Events 스트림.

text/event-stream

401 유효한 활성 API 키가 없습니다(unauthorized).
필드유형필수설명
errorobject예
401 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"
  }
}
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"
  }
}

오류 처리 및 안전한 재시도

중첩 객체

StreamEvent

SSE data의 JSON이며 webhook v1과 다릅니다. 결제 외 이벤트는 payment를 생략하며 contract를 포함할 수 있습니다.

필드유형필수설명
event_idstring예불투명 식별자입니다. 문자열로 유지하세요.
minLength: 1
event_typestring예이벤트 유형입니다. 새로운 유형이 추가될 수 있습니다.
chainstring예네트워크 코드입니다.
servicestring아니요알려진 경우 서비스입니다.
watch_idstring아니요모니터링에 연결된 경우 프로젝트 모니터링 ID입니다.
minLength: 1
occurred_atstring예RFC 3339 형식의 UTC 날짜 및 시간입니다.
date-time
paymentobject | null아니요결제 문서이며, 결제 외 이벤트는 null입니다. GET /events는 contract/notice 본문을 반환하지 않습니다.
sandboxboolean아니요테스트 이벤트입니다. 생략하면 false입니다.
project_idstring아니요불투명 식별자입니다. 문자열로 유지하세요.
minLength: 1
project_namestring아니요프로젝트 이름입니다.
urlstring아니요Account 이벤트 링크입니다.
uri
contractobject아니요
modestring아니요live 또는 test입니다.
live, test
ID

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

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

EventPayment

REST/SSE 결제 문서입니다. 필드는 이벤트와 네트워크에 따라 다르며, 정규화된 웹훅 v1 형식이 아닙니다.

필드유형필수설명
tx_idstring아니요트랜잭션 식별자입니다.
indexinteger아니요트랜잭션 내 전송 인덱스입니다.
minimum: 0
heightinteger아니요확인된 경우 블록 높이입니다.
minimum: 0
addressstring아니요관찰 대상 주소입니다.
assetstring아니요REST/SSE 자산: 웹훅 자산 객체가 아닌 문자열 식별자입니다.
amount_rawstring아니요최소 단위의 정수 금액을 문자열로 표현합니다.
pattern: ^[0-9]+$
amountstring아니요정확한 소수 금액 문자열입니다. 부동 소수점을 사용하지 마세요.
pattern: ^[0-9]+(?:\.[0-9]+)?$
decimalsinteger아니요소수 자릿수입니다.
minimum: 0
confirmationsinteger아니요확인 횟수입니다.
minimum: 0
revisioninteger아니요전송 상태 리비전입니다.
minimum: 0
directionstring아니요관찰 대상 주소를 기준으로 한 방향입니다.
in, out
simulatedboolean아니요시뮬레이션된 이벤트입니다.
lateboolean아니요뒤늦게 감지된 이체입니다.
block_hashstring아니요블록 해시입니다.
match_keystring아니요네트워크에서 사용하는 경우의 매칭 식별자입니다.
metaobject아니요
invoiceobject아니요
customerobject아니요
productobject아니요
payerobject아니요
metadataobject아니요
RawAmount

string

Decimal

string

StringMap

object

Customer

필드유형필수설명
idstring예귀하의 시스템에서 사용하는 고객 식별자입니다.
maxLength: 120
Product

필드유형필수설명
idstring아니요사용자 시스템의 제품 식별자입니다.
maxLength: 120
namestring아니요제품 이름입니다.
maxLength: 200
quantityinteger아니요수량입니다.
minimum: 1; maximum: 1000000
Payer

필드유형필수설명
commentstring예결제자 의견입니다.
maxLength: 500
Error

필드유형필수설명
errorobject예