Petnow LogoPetnow

Biometric Upload

Upload fingerprint (nose) and appearance images using the Petnow API.

Overview

This API allows you to upload pet biometric data (fingerprint/nose images, appearance images). You must create a capture session before uploading.

All calls on this page run on your app server with the x-petnow-api-key header. Do not call them directly from a client app (that would expose the API key). A mobile/RN client sends the captured file:// images to your app server, which then uploads them via the endpoints below.

Create Capture Session

Create a capture session before uploading biometric data.

Endpoint: POST /v2/capture-sessions

Request

curl -X POST "https://api.petify.petnow.io/v2/capture-sessions" \
  -H "x-petnow-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "species": "DOG",
    "purpose": "PET_PROFILE_REGISTRATION",
    "petId": "pet-uuid-1234"
  }'
import requests

url = "https://api.petify.petnow.io/v2/capture-sessions"
headers = {
    "x-petnow-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json"
}
data = {
    "species": "DOG",
    "purpose": "PET_PROFILE_REGISTRATION",
    "petId": "pet-uuid-1234"
}

response = requests.post(url, headers=headers, json=data)
result = response.json()
session_id = result["data"]["id"]
print(f"Session ID: {session_id}")
const response = await fetch("https://api.petify.petnow.io/v2/capture-sessions", {
  method: "POST",
  headers: {
    "x-petnow-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    species: "DOG",
    purpose: "PET_PROFILE_REGISTRATION",
    petId: "pet-uuid-1234"
  })
});

const result = await response.json();
const sessionId = result.data.id;
console.log(`Session ID: ${sessionId}`);

Request Parameters

FieldTypeRequiredDescription
speciesstring✅Species: DOG or CAT
purposestring✅Purpose (see table below)
petIdstringConditionalRequired for registration/verification

Purpose Values

PurposeDescriptionPet ID
PET_PROFILE_REGISTRATIONRegister new petRequired
PET_VERIFICATIONVerify specific pet (1:1)Required
PET_IDENTIFICATIONIdentify pet (1:N)Not required

Response

{
  "success": true,
  "data": {
    "id": "session-uuid-abcd"
  }
}

Upload Fingerprint (Nose) Image

Upload a pet's nose (fingerprint) image.

Endpoint: POST /v2/fingerprints:upload?sessionId={sessionId}

Required: The sessionId query parameter is always required. Uploaded files are automatically linked to the session.

Request

curl -X POST "https://api.petify.petnow.io/v2/fingerprints:upload?sessionId=session-uuid-abcd" \
  -H "x-petnow-api-key: YOUR_API_KEY" \
  -F "file=@/path/to/nose_image.jpg"
import requests

session_id = "session-uuid-abcd"
url = f"https://api.petify.petnow.io/v2/fingerprints:upload?sessionId={session_id}"
headers = {
    "x-petnow-api-key": "YOUR_API_KEY"
}

with open("/path/to/nose_image.jpg", "rb") as f:
    files = {"file": ("nose_image.jpg", f, "image/jpeg")}
    response = requests.post(url, headers=headers, files=files)

result = response.json()
fingerprint_id = result["data"]["id"]
print(f"Fingerprint ID: {fingerprint_id}")
const sessionId = "session-uuid-abcd";
const formData = new FormData();
formData.append("file", fileBlob, "nose_image.jpg");

const response = await fetch(
  `https://api.petify.petnow.io/v2/fingerprints:upload?sessionId=${sessionId}`,
  {
    method: "POST",
    headers: {
      "x-petnow-api-key": "YOUR_API_KEY"
    },
    body: formData
  }
);

const result = await response.json();
const fingerprintId = result.data.id;
console.log(`Fingerprint ID: ${fingerprintId}`);

Request Parameters

FieldTypeRequiredDescription
sessionIdstring (query)✅Capture session ID
filefile✅Fingerprint (nose) image file (JPEG)

Response

{
  "success": true,
  "data": {
    "id": "fingerprint-uuid-1234"
  }
}

Upload Count: Minimum 5 fingerprint images for registration, minimum 3 for verification/identification. More images improve recognition accuracy. An appearance image is also required for every purpose — upload the appearance images the UI module provides; you do not need to track the count.

Upload Appearance Image

Upload the pet's appearance image. This is required for every capture session — registration/fingerprint addition, verification, and identification. Upload the appearance images the UI module provides; omitting them causes the action to fail with CaptureSessionIsNotFinishedException (PETNOWB2B20012).

Endpoint: POST /v2/appearances:upload?sessionId={sessionId}

Request

curl -X POST "https://api.petify.petnow.io/v2/appearances:upload?sessionId=session-uuid-abcd" \
  -H "x-petnow-api-key: YOUR_API_KEY" \
  -F "file=@/path/to/pet_photo.jpg"
import requests

session_id = "session-uuid-abcd"
url = f"https://api.petify.petnow.io/v2/appearances:upload?sessionId={session_id}"
headers = {
    "x-petnow-api-key": "YOUR_API_KEY"
}

with open("/path/to/pet_photo.jpg", "rb") as f:
    files = {"file": ("pet_photo.jpg", f, "image/jpeg")}
    response = requests.post(url, headers=headers, files=files)

result = response.json()
appearance_id = result["data"]["id"]
print(f"Appearance ID: {appearance_id}")
const sessionId = "session-uuid-abcd";
const formData = new FormData();
formData.append("file", fileBlob, "pet_photo.jpg");

const response = await fetch(
  `https://api.petify.petnow.io/v2/appearances:upload?sessionId=${sessionId}`,
  {
    method: "POST",
    headers: {
      "x-petnow-api-key": "YOUR_API_KEY"
    },
    body: formData
  }
);

const result = await response.json();
const appearanceId = result.data.id;
console.log(`Appearance ID: ${appearanceId}`);

Request Parameters

FieldTypeRequiredDescription
sessionIdstring (query)✅Capture session ID
filefile✅Appearance image file (JPEG)

Response

{
  "success": true,
  "data": {
    "id": "appearance-uuid-5678"
  }
}

Complete Upload Flow Example

Automatic Session Linking: When uploading with the sessionId query parameter, files are automatically linked to the session. No separate session end API call is required.

Finish every upload before you start a job: start registration, verification, or identification only after every upload below has returned 201. The job may not use an image that arrives after the job call. If you upload in parallel, wait for all uploads to finish first. See Registration/Verification/Identification.

import requests
from pathlib import Path

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

def upload_biometrics(pet_id: str, fingerprint_files: list, appearance_files: list):
    # 1. Create capture session
    session_response = requests.post(
        f"{BASE_URL}/v2/capture-sessions",
        headers={**HEADERS, "Content-Type": "application/json"},
        json={
            "species": "DOG",
            "purpose": "PET_PROFILE_REGISTRATION",
            "petId": pet_id
        }
    )
    session_id = session_response.json()["data"]["id"]
    print(f"Created session: {session_id}")

    # 2. Upload fingerprints (auto-linked via sessionId query parameter)
    fingerprint_ids = []
    for file_path in fingerprint_files:
        with open(file_path, "rb") as f:
            response = requests.post(
                f"{BASE_URL}/v2/fingerprints:upload?sessionId={session_id}",
                headers=HEADERS,
                files={"file": (Path(file_path).name, f, "image/jpeg")}
            )
            fp_id = response.json()["data"]["id"]
            fingerprint_ids.append(fp_id)
            print(f"Uploaded fingerprint: {fp_id}")

    # 3. Upload appearances (auto-linked via sessionId query parameter)
    appearance_ids = []
    for file_path in appearance_files:
        with open(file_path, "rb") as f:
            response = requests.post(
                f"{BASE_URL}/v2/appearances:upload?sessionId={session_id}",
                headers=HEADERS,
                files={"file": (Path(file_path).name, f, "image/jpeg")}
            )
            ap_id = response.json()["data"]["id"]
            appearance_ids.append(ap_id)
            print(f"Uploaded appearance: {ap_id}")

    return session_id, fingerprint_ids, appearance_ids

# Usage example
session_id, fp_ids, ap_ids = upload_biometrics(
    pet_id="pet-uuid-1234",
    fingerprint_files=["nose1.jpg", "nose2.jpg", "nose3.jpg", "nose4.jpg", "nose5.jpg"],
    appearance_files=["full_body.jpg"]
)
const API_KEY = "YOUR_API_KEY";
const BASE_URL = "https://api.petify.petnow.io";

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

  // 1. Create capture session
  const sessionResponse = await fetch(`${BASE_URL}/v2/capture-sessions`, {
    method: "POST",
    headers: { ...headers, "Content-Type": "application/json" },
    body: JSON.stringify({
      species: "DOG",
      purpose: "PET_PROFILE_REGISTRATION",
      petId: petId
    })
  });
  const sessionId = (await sessionResponse.json()).data.id;
  console.log(`Created session: ${sessionId}`);

  // 2. Upload fingerprints (auto-linked via sessionId query parameter)
  const fingerprintIds = [];
  for (const file of fingerprintFiles) {
    const formData = new FormData();
    formData.append("file", file);

    const response = await fetch(
      `${BASE_URL}/v2/fingerprints:upload?sessionId=${sessionId}`,
      {
        method: "POST",
        headers: headers,
        body: formData
      }
    );
    const fpId = (await response.json()).data.id;
    fingerprintIds.push(fpId);
    console.log(`Uploaded fingerprint: ${fpId}`);
  }

  // 3. Upload appearances (auto-linked via sessionId query parameter)
  const appearanceIds = [];
  for (const file of appearanceFiles) {
    const formData = new FormData();
    formData.append("file", file);

    const response = await fetch(
      `${BASE_URL}/v2/appearances:upload?sessionId=${sessionId}`,
      {
        method: "POST",
        headers: headers,
        body: formData
      }
    );
    const apId = (await response.json()).data.id;
    appearanceIds.push(apId);
    console.log(`Uploaded appearance: ${apId}`);
  }

  return { sessionId, fingerprintIds, appearanceIds };
}

Next Steps

On this page