Transfers
Create and track custody transfers with hash-chain integrity verification.
Overview
Transfers represent custody transfer events in the chain of custody. Each transfer:
- Records a custody event (PICKUP, CHECKPOINT, HANDOFF, DELIVERY)
- Links to a credential for authorization
- Maintains hash-chain integrity
- Tracks transfer sessions
Transfer types follow a logical sequence: PICKUP → CHECKPOINT(s) → HANDOFF(s) → DELIVERY.
Methods
create()
Create a custody transfer event.
vinstrrequired17-character Vehicle Identification Number (excludes I, O, Q)
transfer_typeTransferTyperequiredType of transfer: PICKUP, CHECKPOINT, HANDOFF, or DELIVERY
credential_idstrrequiredID of the credential authorizing this transfer
location_idstrrequiredLocation ID where transfer occurs (format: LOC-{TYPE}-{ID})
timestampdatetimeWhen the transfer occurred (default: server time)
metadatadictAdditional metadata for the transfer (optional)
Returns: Transfer object with transfer_id, session_id, hashes, etc.
Example:
from vecu_custody import CustodyClient, TransferType
client = CustodyClient.sandbox(token="your-jwt-token")
# Create initial pickup
transfer = client.transfers.create(
vin="9HGBH41JXMN999999",
transfer_type=TransferType.PICKUP,
credential_id="CRED-12345678",
location_id="LOC-AUCTION-MANHEIM-ATLANTA",
metadata={"notes": "Vehicle in good condition"}
)
print(f"Transfer ID: {transfer.transfer_id}")
print(f"Session ID: {transfer.session_id}")
print(f"Event hash: {transfer.event_hash}")
# Later, create delivery
delivery = client.transfers.create(
vin="9HGBH41JXMN999999",
transfer_type=TransferType.DELIVERY,
credential_id="CRED-87654321",
location_id="LOC-DEALERSHIP-CARMAX-ORLANDO"
)
get_status()
Get current custody status for a VIN.
vinstrrequired17-character Vehicle Identification Number
Returns: CustodyStatus object with current custodian, location, etc.
Example:
from vecu_custody import CustodyClient
client = CustodyClient.sandbox(token="your-jwt-token")
status = client.transfers.get_status("9HGBH41JXMN999999")
if status.current_custodian:
print(f"Current custodian: {status.current_custodian}")
print(f"Location: {status.current_location}")
print(f"Total transfers: {status.transfer_count}")
else:
print("No custody record for this VIN")
get_history()
Get transfer history for a VIN with pagination support.
vinstrrequired17-character Vehicle Identification Number
limitintNumber of items per page (default: 50, max: 100)
next_tokenstrPagination cursor from previous response
auto_paginateboolIf True, returns iterator; if False, returns single page. Default: True
Returns: Iterator of Transfer objects (if auto_paginate=True) or TransferHistoryResponse (if auto_paginate=False)
Example:
from vecu_custody import CustodyClient
client = CustodyClient.sandbox(token="your-jwt-token")
# Auto-paginate through all transfers
for transfer in client.transfers.get_history("9HGBH41JXMN999999"):
print(f"{transfer.transfer_type} at {transfer.created_at}")
print(f" Location: {transfer.location_id}")
print(f" Hash: {transfer.event_hash}")
# Manual pagination
page = client.transfers.get_history(
"9HGBH41JXMN999999",
limit=20,
auto_paginate=False
)
print(f"Total transfers: {page.total_count}")
if page.next_token:
next_page = client.transfers.get_history(
"9HGBH41JXMN999999",
next_token=page.next_token,
auto_paginate=False
)
verify_integrity()
Verify hash-chain integrity for a VIN.
vinstrrequired17-character Vehicle Identification Number
Returns: IntegrityVerification object indicating if chain is valid
Example:
from vecu_custody import CustodyClient
client = CustodyClient.sandbox(token="your-jwt-token")
verification = client.transfers.verify_integrity("9HGBH41JXMN999999")
if verification.chain_valid:
print(f"Chain valid: {verification.total_events} events verified")
else:
print(f"Chain integrity error: {verification.error_message}")
Response Objects
Transfer
transfer_idstrUnique identifier for the transfer (e.g., "TRF-12345678")
session_idstrSession ID linking related transfers
vinstrVehicle Identification Number
transfer_typeTransferTypeType: PICKUP, CHECKPOINT, HANDOFF, or DELIVERY
statusstrTransfer status (e.g., "COMPLETED")
credential_idstrCredential ID authorizing the transfer
location_idstrLocation where transfer occurred
event_hashstrSHA-256 hash of this transfer event
previous_hashstrHash of the previous transfer in the chain
metadatadictCustom metadata (if provided)
created_atstrISO 8601 timestamp when transfer was created
CustodyStatus
vinstrVehicle Identification Number
session_idstrCurrent session ID
statusstrCustody status (e.g., "IN_CUSTODY")
current_custodianstrCurrent custodian credential ID
current_locationstrCurrent location ID
last_transfer_atstrISO 8601 timestamp of last transfer
transfer_countintTotal number of transfers for this VIN
IntegrityVerification
vinstrVehicle Identification Number
chain_validboolWhether the custody chain is valid
total_eventsintNumber of events verified
error_messagestrError message if chain is invalid (null if valid)
Common Use Cases
Complete Transfer Flow
from vecu_custody import CustodyClient, TransferType
client = CustodyClient.sandbox(token="your-jwt-token")
vin = "9HGBH41JXMN999999"
# Step 1: Pickup at origin
pickup = client.transfers.create(
vin=vin,
transfer_type=TransferType.PICKUP,
credential_id="CRED-DRIVER-123",
location_id="LOC-AUCTION-MANHEIM-ATLANTA"
)
print(f"Pickup transfer: {pickup.transfer_id}")
# Step 2: Checkpoint during transport
checkpoint = client.transfers.create(
vin=vin,
transfer_type=TransferType.CHECKPOINT,
credential_id="CRED-DRIVER-123",
location_id="LOC-TRUCK-STOP-I75"
)
# Step 3: Delivery at destination
delivery = client.transfers.create(
vin=vin,
transfer_type=TransferType.DELIVERY,
credential_id="CRED-RECEIVER-456",
location_id="LOC-DEALERSHIP-CARMAX-ORLANDO"
)
print(f"Delivery transfer: {delivery.transfer_id}")
# Verify integrity
verification = client.transfers.verify_integrity(vin)
print(f"Chain valid: {verification.chain_valid}")
View Transfer History
# Get complete history
history = list(client.transfers.get_history("9HGBH41JXMN999999"))
print(f"Transfer Chain for VIN: 9HGBH41JXMN999999")
print(f"Total transfers: {len(history)}\n")
for i, transfer in enumerate(history, 1):
print(f"{i}. {transfer.transfer_type}")
print(f" Location: {transfer.location_id}")
print(f" Date: {transfer.created_at}")
print(f" Hash: {transfer.event_hash[:16]}...")
print()
Check Current Status
status = client.transfers.get_status("9HGBH41JXMN999999")
print(f"Current Status:")
print(f" Custodian: {status.current_custodian}")
print(f" Location: {status.current_location}")
print(f" Last transfer: {status.last_transfer_at}")
print(f" Total transfers: {status.transfer_count}")
Error Handling
from vecu_custody import CustodyClient, TransferType
from vecu_custody.exceptions import (
InvalidTransferSequenceError,
SessionAlreadyClosedError,
ValidationError
)
client = CustodyClient.sandbox(token="your-jwt-token")
try:
transfer = client.transfers.create(
vin="9HGBH41JXMN999999",
transfer_type=TransferType.DELIVERY,
credential_id="CRED-12345678",
location_id="LOC-DEALERSHIP-CARMAX-ORLANDO"
)
except InvalidTransferSequenceError as e:
print(f"Invalid sequence: {e.message}")
print("You must create a PICKUP before DELIVERY")
except SessionAlreadyClosedError as e:
print(f"Session closed: {e.session_id}")
except ValidationError as e:
print(f"Invalid parameters: {e.message}")
Next Steps
- Custody Permits - Create authorizations for transfers
- Releasability - Check vehicle releasability