Petnow LogoPetnow
Server API

등록/검증/식별

반려동물 지문 등록, 검증(1:1), 식별(1:N) API를 안내합니다.

개요

Petnow API는 세 가지 핵심 기능을 제공합니다:

기능설명용도
등록 (Registration)펫에 지문 추가새 반려동물 등록
검증 (Verification)1:1 매칭"이 펫이 맞는지" 확인
식별 (Identification)1:N 매칭"이 펫이 누구인지" 찾기

지문 등록 (Add Fingerprints)

캡처 세션의 지문을 펫에 추가합니다.

엔드포인트: POST /v2/pets/{petId}:addFingerprints

전체 플로우

요청

curl -X POST "https://api.petify.petnow.io/v2/pets/pet-uuid-1234:addFingerprints" \
  -H "x-petnow-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sessionId": "session-uuid-abcd"
  }'
import requests
import time

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.petify.petnow.io"
HEADERS = {"x-petnow-api-key": API_KEY}

def add_fingerprints(pet_id: str, session_id: str):
    # 지문 추가 요청
    response = requests.post(
        f"{BASE_URL}/v2/pets/{pet_id}:addFingerprints",
        headers={**HEADERS, "Content-Type": "application/json"},
        json={"sessionId": session_id}
    )
    job_id = response.json()["data"]["jobId"]
    print(f"Job started: {job_id}")

    # 작업 상태 폴링
    while True:
        status_response = requests.get(
            f"{BASE_URL}/v2/fingerprint-addition-jobs/{job_id}",
            headers=HEADERS
        )
        result = status_response.json()["data"]
        status = result["status"]
        
        print(f"Status: {status}")
        
        if status == "SUCCESS":
            print("Fingerprints added successfully!")
            return result
        elif status == "FAILED":
            raise Exception(f"Job failed: {result.get('error')}")
        
        time.sleep(2)  # 2초 대기

# 사용 예시
result = add_fingerprints("pet-uuid-1234", "session-uuid-abcd")
const API_KEY = "YOUR_API_KEY";
const BASE_URL = "https://api.petify.petnow.io";

async function addFingerprints(petId, sessionId) {
  const headers = { "x-petnow-api-key": API_KEY };

  // 지문 추가 요청
  const response = await fetch(
    `${BASE_URL}/v2/pets/${petId}:addFingerprints`,
    {
      method: "POST",
      headers: { ...headers, "Content-Type": "application/json" },
      body: JSON.stringify({ sessionId })
    }
  );
  const jobId = (await response.json()).data.jobId;
  console.log(`Job started: ${jobId}`);

  // 작업 상태 폴링
  while (true) {
    const statusResponse = await fetch(
      `${BASE_URL}/v2/fingerprint-addition-jobs/${jobId}`,
      { headers }
    );
    const result = (await statusResponse.json()).data;
    const status = result.status;
    
    console.log(`Status: ${status}`);
    
    if (status === "SUCCESS") {
      console.log("Fingerprints added successfully!");
      return result;
    } else if (status === "FAILED") {
      throw new Error(`Job failed: ${result.error}`);
    }
    
    await new Promise(resolve => setTimeout(resolve, 2000)); // 2초 대기
  }
}

// 사용 예시
const result = await addFingerprints("pet-uuid-1234", "session-uuid-abcd");

응답 (작업 시작)

{
  "data": {
    "jobId": "job-uuid-1234"
  }
}

작업 상태 조회 응답

{
  "data": {
    "status": "SUCCESS",
    "petId": "pet-uuid-1234",
    "addedCount": 5
  }
}

펫 검증 (Verification)

캡처된 생체 정보가 특정 펫과 일치하는지 확인합니다 (1:1 매칭).

엔드포인트: POST /v2/pets/{petId}:verify

전체 플로우

요청

curl -X POST "https://api.petify.petnow.io/v2/pets/pet-uuid-1234:verify" \
  -H "x-petnow-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sessionId": "session-uuid-abcd"
  }'
import requests
import time

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.petify.petnow.io"
HEADERS = {"x-petnow-api-key": API_KEY}

def verify_pet(pet_id: str, session_id: str):
    # 검증 요청
    response = requests.post(
        f"{BASE_URL}/v2/pets/{pet_id}:verify",
        headers={**HEADERS, "Content-Type": "application/json"},
        json={"sessionId": session_id}
    )
    job_id = response.json()["data"]["jobId"]
    print(f"Verification job started: {job_id}")

    # 작업 상태 폴링
    while True:
        status_response = requests.get(
            f"{BASE_URL}/v2/verification-jobs/{job_id}",
            headers=HEADERS
        )
        result = status_response.json()["data"]
        status = result["status"]
        
        if status == "SUCCESS":
            is_verified = result["isVerified"]
            score = result["score"]
            print(f"Verified: {is_verified}, Score: {score}")
            return result
        elif status == "FAILED":
            raise Exception(f"Verification failed: {result.get('error')}")
        
        time.sleep(2)

# 사용 예시
result = verify_pet("pet-uuid-1234", "session-uuid-abcd")
if result["isVerified"]:
    print("✅ 본인 확인 완료!")
else:
    print("❌ 일치하지 않음")
const API_KEY = "YOUR_API_KEY";
const BASE_URL = "https://api.petify.petnow.io";

async function verifyPet(petId, sessionId) {
  const headers = { "x-petnow-api-key": API_KEY };

  // 검증 요청
  const response = await fetch(
    `${BASE_URL}/v2/pets/${petId}:verify`,
    {
      method: "POST",
      headers: { ...headers, "Content-Type": "application/json" },
      body: JSON.stringify({ sessionId })
    }
  );
  const jobId = (await response.json()).data.jobId;
  console.log(`Verification job started: ${jobId}`);

  // 작업 상태 폴링
  while (true) {
    const statusResponse = await fetch(
      `${BASE_URL}/v2/verification-jobs/${jobId}`,
      { headers }
    );
    const result = (await statusResponse.json()).data;
    
    if (result.status === "SUCCESS") {
      console.log(`Verified: ${result.isVerified}, Score: ${result.score}`);
      return result;
    } else if (result.status === "FAILED") {
      throw new Error(`Verification failed: ${result.error}`);
    }
    
    await new Promise(resolve => setTimeout(resolve, 2000));
  }
}

// 사용 예시
const result = await verifyPet("pet-uuid-1234", "session-uuid-abcd");
if (result.isVerified) {
  console.log("✅ 본인 확인 완료!");
} else {
  console.log("❌ 일치하지 않음");
}

검증 결과 응답

{
  "data": {
    "status": "SUCCESS",
    "isVerified": true,
    "score": 95
  }
}
필드타입설명
statusstringPENDING, SUCCESS, FAILED
isVerifiedboolean일치 여부
scorenumber신뢰도 점수 (0-100)

펫 식별 (Identification)

데이터베이스에서 캡처된 생체 정보와 일치하는 펫을 찾습니다 (1:N 매칭).

엔드포인트: POST /v2/pets:identify

전체 플로우

요청

curl -X POST "https://api.petify.petnow.io/v2/pets:identify" \
  -H "x-petnow-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sessionId": "session-uuid-abcd"
  }'
import requests
import time

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.petify.petnow.io"
HEADERS = {"x-petnow-api-key": API_KEY}

def identify_pet(session_id: str):
    # 식별 요청
    response = requests.post(
        f"{BASE_URL}/v2/pets:identify",
        headers={**HEADERS, "Content-Type": "application/json"},
        json={"sessionId": session_id}
    )
    job_id = response.json()["data"]["jobId"]
    print(f"Identification job started: {job_id}")

    # 작업 상태 폴링
    while True:
        status_response = requests.get(
            f"{BASE_URL}/v2/identification-jobs/{job_id}",
            headers=HEADERS
        )
        result = status_response.json()["data"]
        status = result["status"]
        
        if status == "SUCCESS":
            pets = result.get("pets", [])
            print(f"Found {len(pets)} matching pet(s)")
            for pet in pets:
                print(f"  - {pet['id']}: score={pet['score']}")
            return result
        elif status == "FAILED":
            raise Exception(f"Identification failed: {result.get('error')}")
        
        time.sleep(2)

# 사용 예시
result = identify_pet("session-uuid-abcd")
if result["pets"]:
    best_match = result["pets"][0]
    print(f"Best match: {best_match['id']} (score: {best_match['score']})")
else:
    print("No matching pets found")
const API_KEY = "YOUR_API_KEY";
const BASE_URL = "https://api.petify.petnow.io";

async function identifyPet(sessionId) {
  const headers = { "x-petnow-api-key": API_KEY };

  // 식별 요청
  const response = await fetch(
    `${BASE_URL}/v2/pets:identify`,
    {
      method: "POST",
      headers: { ...headers, "Content-Type": "application/json" },
      body: JSON.stringify({ sessionId })
    }
  );
  const jobId = (await response.json()).data.jobId;
  console.log(`Identification job started: ${jobId}`);

  // 작업 상태 폴링
  while (true) {
    const statusResponse = await fetch(
      `${BASE_URL}/v2/identification-jobs/${jobId}`,
      { headers }
    );
    const result = (await statusResponse.json()).data;
    
    if (result.status === "SUCCESS") {
      const pets = result.pets || [];
      console.log(`Found ${pets.length} matching pet(s)`);
      pets.forEach(pet => {
        console.log(`  - ${pet.id}: score=${pet.score}`);
      });
      return result;
    } else if (result.status === "FAILED") {
      throw new Error(`Identification failed: ${result.error}`);
    }
    
    await new Promise(resolve => setTimeout(resolve, 2000));
  }
}

// 사용 예시
const result = await identifyPet("session-uuid-abcd");
if (result.pets?.length > 0) {
  const bestMatch = result.pets[0];
  console.log(`Best match: ${bestMatch.id} (score: ${bestMatch.score})`);
} else {
  console.log("No matching pets found");
}

식별 결과 응답

{
  "data": {
    "status": "SUCCESS",
    "pets": [
      {
        "id": "pet-uuid-1234",
        "score": 95,
        "metadata": "{\"name\": \"버디\", \"owner\": \"홍길동\"}"
      },
      {
        "id": "pet-uuid-5678",
        "score": 78,
        "metadata": "{\"name\": \"맥스\", \"owner\": \"김영희\"}"
      }
    ]
  }
}
필드타입설명
petsarray매칭된 펫 목록 (점수 내림차순)
pets[].idstring펫 ID
pets[].scorenumber신뢰도 점수 (0-100)
pets[].metadatastring펫 메타데이터 (JSON 문자열)

작업 상태 값

모든 비동기 작업은 다음 상태를 가집니다:

상태설명
PENDING처리 중
SUCCESS성공
FAILED실패

권장 폴링 설정

항목권장값
폴링 간격2-3초
최대 대기 시간60초
최대 재시도 횟수20-30회

: 지수 백오프(exponential backoff)를 사용하면 서버 부하를 줄이고 효율적으로 폴링할 수 있습니다. 초기 간격 1초에서 시작하여 최대 5초까지 증가시키는 방식을 권장합니다.

다음 단계

On this page