API 참조

웹훅 엔드포인트 생성

POST/v1/endpoints

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

이 페이지에서

프로젝트 HTTPS 수신자를 추가하세요. 계정당 최대 20개의 활성 엔드포인트를 허용합니다. 같은 API 키로 같은 프로젝트의 동일 URL을 다시 등록해도 전달이 중복되지 않습니다. 200은 기존 ID를 반환하며 비밀 값은 없습니다. 201 후 비밀 값을 저장하세요. 한도에 도달하면 재등록도 402을 반환할 수 있습니다.

키 권한: webhooks / write.

요청 본문

필드유형필수설명
urlstring예공개 HTTPS 웹훅 수신 URL입니다. 로컬 및 비공개 주소는 거부됩니다.
uri; pattern: ^https://
labelstring아니요선택적 대상 이름입니다.
projectstring아니요프로젝트 ID입니다. 생략하면 키의 프로젝트 또는 계정의 기본 프로젝트를 사용합니다.
application/json
{
  "project": "1002",
  "url": "https://merchant.example/webhooks/cryptanio",
  "label": "Orders"
}

요청 예시

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

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")"',"url":"https://merchant.example/webhooks/cryptanio","label":"Orders"}' \
  "https://api.cryptanio.com/v1/endpoints" \
  --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/endpoints"

    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\",\"url\":\"https://merchant.example/webhooks/cryptanio\",\"label\":\"Orders\"}"), &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("endpoints");
    }
    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\",\"url\":\"https://merchant.example/webhooks/cryptanio\",\"label\":\"Orders\"}")?;
    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/endpoints';

    $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","url":"https://merchant.example/webhooks/cryptanio","label":"Orders"}', 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/endpoints"

    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\",\"url\":\"https://merchant.example/webhooks/cryptanio\",\"label\":\"Orders\"}")
    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/endpoints";

  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",
    "url": "https://merchant.example/webhooks/cryptanio",
    "label": "Orders"
  };
  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;
}
예제 다운로드

응답 및 오류

200 이미 등록된 엔드포인트이며 비밀 값은 제외됩니다.
필드유형필수설명
idstring예불투명 식별자입니다. 문자열로 유지하세요.
minLength: 1
project_idstring예불투명 식별자입니다. 문자열로 유지하세요.
minLength: 1
sandboxboolean예테스트 대상 표시입니다. 공개 고객 샌드박스 제공을 의미하지 않습니다.
urlstring예대상 HTTPS URL입니다.
uri
labelstring아니요라벨입니다.
secretstring아니요서명 비밀 값입니다. 새로 생성할 때만 반환하며 목록이나 반복 등록에는 반환하지 않습니다.
sourcestring예api, dashboard, browser 등 대상 생성 방식입니다. 새로운 값이 추가될 수 있습니다.
created_atstring예RFC 3339 형식의 UTC 날짜 및 시간입니다.
date-time
200 application/json
{
  "id": "2200",
  "project_id": "1002",
  "sandbox": true,
  "url": "https://merchant.example/webhooks/cryptanio",
  "source": "api",
  "created_at": "2026-10-06T10:00:00Z"
}
201 성공 응답.
필드유형필수설명
idstring예불투명 식별자입니다. 문자열로 유지하세요.
minLength: 1
project_idstring예불투명 식별자입니다. 문자열로 유지하세요.
minLength: 1
sandboxboolean예테스트 대상 표시입니다. 공개 고객 샌드박스 제공을 의미하지 않습니다.
urlstring예대상 HTTPS URL입니다.
uri
labelstring아니요라벨입니다.
secretstring아니요서명 비밀 값입니다. 새로 생성할 때만 반환하며 목록이나 반복 등록에는 반환하지 않습니다.
sourcestring예api, dashboard, browser 등 대상 생성 방식입니다. 새로운 값이 추가될 수 있습니다.
created_atstring예RFC 3339 형식의 UTC 날짜 및 시간입니다.
date-time
201 application/json
{
  "id": "2200",
  "project_id": "1002",
  "sandbox": true,
  "url": "https://merchant.example/webhooks/cryptanio",
  "source": "api",
  "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"
  }
}

오류 처리 및 안전한 재시도

중첩 객체

Endpoint

필드유형필수설명
idstring예불투명 식별자입니다. 문자열로 유지하세요.
minLength: 1
project_idstring예불투명 식별자입니다. 문자열로 유지하세요.
minLength: 1
sandboxboolean예테스트 대상 표시입니다. 공개 고객 샌드박스 제공을 의미하지 않습니다.
urlstring예대상 HTTPS URL입니다.
uri
labelstring아니요라벨입니다.
secretstring아니요서명 비밀 값입니다. 새로 생성할 때만 반환하며 목록이나 반복 등록에는 반환하지 않습니다.
sourcestring예api, dashboard, browser 등 대상 생성 방식입니다. 새로운 값이 추가될 수 있습니다.
created_atstring예RFC 3339 형식의 UTC 날짜 및 시간입니다.
date-time
ID

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

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

EndpointRequest

필드유형필수설명
urlstring예공개 HTTPS 웹훅 수신 URL입니다. 로컬 및 비공개 주소는 거부됩니다.
uri; pattern: ^https://
labelstring아니요선택적 대상 이름입니다.
projectstring아니요프로젝트 ID입니다. 생략하면 키의 프로젝트 또는 계정의 기본 프로젝트를 사용합니다.
Error

필드유형필수설명
errorobject예