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
}
}| 필드 | 타입 | 설명 |
|---|---|---|
status | string | PENDING, SUCCESS, FAILED |
isVerified | boolean | 일치 여부 |
score | number | 신뢰도 점수 (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\": \"김영희\"}"
}
]
}
}| 필드 | 타입 | 설명 |
|---|---|---|
pets | array | 매칭된 펫 목록 (점수 내림차순) |
pets[].id | string | 펫 ID |
pets[].score | number | 신뢰도 점수 (0-100) |
pets[].metadata | string | 펫 메타데이터 (JSON 문자열) |
작업 상태 값
모든 비동기 작업은 다음 상태를 가집니다:
| 상태 | 설명 |
|---|---|
PENDING | 처리 중 |
SUCCESS | 성공 |
FAILED | 실패 |
권장 폴링 설정
| 항목 | 권장값 |
|---|---|
| 폴링 간격 | 2-3초 |
| 최대 대기 시간 | 60초 |
| 최대 재시도 횟수 | 20-30회 |
팁: 지수 백오프(exponential backoff)를 사용하면 서버 부하를 줄이고 효율적으로 폴링할 수 있습니다. 초기 간격 1초에서 시작하여 최대 5초까지 증가시키는 방식을 권장합니다.