Releasability

Query and update vehicle releasability status based on origin location context.

SDK-Only Access

To ensure your integration remains stable and supported, always use the official SDKs. The underlying API endpoints are internal implementation details that may change in purpose, functionality, or be removed at any time without notice. Direct API access is not supported. Learn more →

The SDK methods documented here are your supported interface. Versioning is managed through SDK upgrades.

Overview

Releasability operations determine if a vehicle can be released from custody at a given origin. The service evaluates:

  • Origin Location: Geocoded address or coordinates for the release point
  • Blockers: Reasons preventing release (empty when releasable)
  • Source: Whether data came from cache or was not available

Methods

GetReleasabilityAsync()

Get the releasability status for a vehicle at a specific origin.

vinstringrequired

17-character Vehicle Identification Number

originstringrequired

Address string or lat,lng coordinate pair (e.g., "1180 Lake Hearn Dr NE, Atlanta, GA 30342" or "33.8463,-84.3621")

cancellationTokenCancellationToken

Optional cancellation token for the async operation

Returns: ReleasabilityResponse

Exceptions:

  • ArgumentException - VIN or origin is null or whitespace
  • ValidationException - Invalid request parameters (400, 422)
  • AuthException - Authentication failure (401)
  • RateLimitException - Rate limit exceeded (429)
  • NetworkException - Network or server errors (5xx)

Example:

using CoxAuto.Vecu.CustodySdk.Client;

public class ReleasabilityService
{
    private readonly ICustodyServiceClient _client;

    public ReleasabilityService(ICustodyServiceClient client)
    {
        _client = client;
    }

    public async Task<bool> CheckVehicleReleasability(string vin)
    {
        var result = await _client.GetReleasabilityAsync(
            vin,
            origin: "1180 Lake Hearn Dr NE, Atlanta, GA 30342");

        Console.WriteLine($"Is releasable: {result.IsReleasable}");
        Console.WriteLine($"Source: {result.Source}");
        Console.WriteLine($"Checked at: {result.CheckedAt}");

        if (!result.IsReleasable)
        {
            Console.WriteLine("Blockers:");
            foreach (var blocker in result.Blockers)
            {
                Console.WriteLine($"  - {blocker}");
            }
        }

        if (result.OriginLocation != null)
        {
            var loc = result.OriginLocation;
            Console.WriteLine($"Geocoded: {loc.FormattedAddress}");
            Console.WriteLine($"Coordinates: {loc.Lat}, {loc.Lng}");
            Console.WriteLine($"Geohash: {loc.Geohash}");
        }

        return result.IsReleasable;
    }
}

UpdateReleasabilityAsync()

Update the releasability status for a vehicle.

vinstringrequired

17-character Vehicle Identification Number

requestUpdateReleasabilityRequestrequired

Update request body with releasability details

cancellationTokenCancellationToken

Optional cancellation token for the async operation

UpdateReleasabilityRequest Properties

OriginAddressstringrequired

Address string or lat,lng coordinate pair

Releasableboolrequired

Whether the vehicle is releasable

DetectedAtDateTimeOffsetrequired

Timestamp when releasability was detected

BlockersIReadOnlyList<string>

Reasons the vehicle cannot be released (when Releasable = false)

ReleaseIdstring

Release record ID (optional)

ReleasabilityCheckUrlstring

URL for full releasability check (optional)

Returns: UpdateReleasabilityResponse

Exceptions:

  • ArgumentNullException - Request is null
  • ValidationException - Invalid request parameters (400, 422)
  • AuthException - Authentication failure (401)
  • RateLimitException - Rate limit exceeded (429)
  • NetworkException - Network or server errors (5xx)

Example:

using CoxAuto.Vecu.CustodySdk.Client;
using CoxAuto.Vecu.CustodySdk.Models.Requests;

public async Task UpdateVehicleReleasability(string vin)
{
    // Mark vehicle as releasable
    var request = new UpdateReleasabilityRequest
    {
        OriginAddress = "1180 Lake Hearn Dr NE, Atlanta, GA 30342",
        Releasable = true,
        DetectedAt = DateTimeOffset.UtcNow,
    };

    var result = await _client.UpdateReleasabilityAsync(vin, request);

    Console.WriteLine($"Updated: {result.Message}");
    Console.WriteLine($"VIN: {result.Vin}");
    Console.WriteLine($"Origin geohash: {result.OriginGeohash}");
}

public async Task MarkVehicleBlocked(string vin)
{
    // Mark vehicle as NOT releasable
    var request = new UpdateReleasabilityRequest
    {
        OriginAddress = "33.8463,-84.3621",
        Releasable = false,
        DetectedAt = DateTimeOffset.UtcNow,
        Blockers = new[] { "Payment not cleared", "Title hold" }
    };

    var result = await _client.UpdateReleasabilityAsync(vin, request);

    Console.WriteLine($"Updated: {result.Message}");
}

Response Objects

ReleasabilityResponse

Returned by GetReleasabilityAsync.

Vinstring

Vehicle Identification Number

Originstring?

Origin address or coordinates (echoed back if provided)

IsReleasablebool

Whether the vehicle can be released

Sourcestring

Data source: "CACHE" or "NOT_AVAILABLE"

BlockersIReadOnlyList<string>

Reasons preventing release (empty when releasable)

CheckedAtDateTimeOffset

Timestamp when releasability was checked

OriginLocationOriginLocation?

Geocoded origin location (if available)

OriginLocation

Geocoded origin location returned in the response.

Addressstring?

Raw address string (if provided)

FormattedAddressstring?

Geocoded formatted address (if available)

Latdouble

Latitude coordinate

Lngdouble

Longitude coordinate

Geohashstring

Geohash encoding of coordinates

UpdateReleasabilityResponse

Returned by UpdateReleasabilityAsync.

Messagestring

Confirmation message

Vinstring

Vehicle Identification Number

Releasablebool

Whether the vehicle is releasable

OriginGeohashstring

Geohash of the geocoded origin address

Common Use Cases

Pre-Transfer Validation

public async Task<(bool CanTransfer, string Message)> CanInitiateTransfer(
    string vin,
    string origin)
{
    try
    {
        var result = await _client.GetReleasabilityAsync(vin, origin);

        if (result.IsReleasable)
        {
            return (true, "Vehicle is releasable");
        }

        var blockers = string.Join(", ", result.Blockers);
        return (false, $"Vehicle not releasable. Blockers: {blockers}");
    }
    catch (ValidationException ex)
    {
        return (false, $"Invalid request: {ex.Message}");
    }
}

Detailed Releasability Report

public async Task PrintReleasabilityReport(string vin, string origin)
{
    var result = await _client.GetReleasabilityAsync(vin, origin);

    Console.WriteLine($"\n=== Releasability Report for VIN: {vin} ===");
    Console.WriteLine($"Status: {(result.IsReleasable ? "RELEASABLE" : "BLOCKED")}");
    Console.WriteLine($"Source: {result.Source}");
    Console.WriteLine($"Checked at: {result.CheckedAt:yyyy-MM-dd HH:mm:ss}");

    if (!result.IsReleasable)
    {
        Console.WriteLine("\n--- Blockers ---");
        foreach (var blocker in result.Blockers)
        {
            Console.WriteLine($"  - {blocker}");
        }
    }

    if (result.OriginLocation != null)
    {
        var loc = result.OriginLocation;
        Console.WriteLine("\n--- Origin Location ---");
        Console.WriteLine($"Address: {loc.FormattedAddress ?? loc.Address}");
        Console.WriteLine($"Coordinates: {loc.Lat}, {loc.Lng}");
        Console.WriteLine($"Geohash: {loc.Geohash}");
    }

    Console.WriteLine("=====================================\n");
}

Validate Before Creating Authorization

public async Task<AuthorizationResponse?> CreateAuthorizationWithValidation(
    string vin,
    string origin,
    string destination,
    string personIdentityKey)
{
    // Check releasability first
    var relResult = await _client.GetReleasabilityAsync(vin, origin);

    if (!relResult.IsReleasable)
    {
        Console.WriteLine("Vehicle is not releasable:");
        foreach (var blocker in relResult.Blockers)
        {
            Console.WriteLine($"  - {blocker}");
        }
        return null;
    }

    // Vehicle is releasable - create authorization
    var authRequest = new CreateAuthorizationRequest
    {
        Vin = vin,
        Origin = origin,
        Destination = destination,
        PersonIdentityKey = personIdentityKey,
        MakeModel = "Toyota Camry",
        AuthorizedBy = "transport-service",
        TransportOrderId = $"TO-{DateTime.UtcNow:yyyyMMddHHmmss}"
    };

    var auth = await _client.CreateAuthorizationAsync(authRequest);

    Console.WriteLine($"Authorization created: {auth.AuthorizationId}");
    return auth;
}

Check Multiple Vehicles in Parallel

public async Task<Dictionary<string, bool>> CheckMultipleVehicles(
    List<string> vins,
    string origin)
{
    var tasks = vins.Select(async vin =>
    {
        try
        {
            var result = await _client.GetReleasabilityAsync(vin, origin);
            return (vin, result.IsReleasable);
        }
        catch
        {
            return (vin, false);
        }
    });

    var results = await Task.WhenAll(tasks);

    return results.ToDictionary(r => r.vin, r => r.Item2);
}

Error Handling

using CoxAuto.Vecu.CustodySdk.Exceptions;

public async Task<ReleasabilityResponse?> GetReleasabilityWithErrorHandling(
    string vin,
    string origin)
{
    try
    {
        return await _client.GetReleasabilityAsync(vin, origin);
    }
    catch (ArgumentException ex)
    {
        Console.WriteLine($"Invalid arguments: {ex.Message}");
        return null;
    }
    catch (ValidationException ex)
    {
        Console.WriteLine($"Invalid request: {ex.Message}");
        return null;
    }
    catch (RateLimitException ex)
    {
        Console.WriteLine($"Rate limited. Retry after: {ex.RetryAfter}");
        return null;
    }
    catch (NetworkException ex)
    {
        Console.WriteLine($"Network error: {ex.Message}");
        return null;
    }
}

Next Steps