advanced
integrations
api
partner

Partner API Integration

Integrate your systems with Levy Fleets using our Partner API - manage vehicles, rides, customers, and receive real-time webhooks

Levy Fleets Team25 de diciembre de 202512 min read

Partner API Integration

The Partner API allows external systems to integrate with Levy Fleets, enabling programmatic access to vehicles, rides, customers, zones, and pricing data. Use webhooks to receive real-time notifications of fleet events.

Overview

The Partner API provides RESTful endpoints for managing your fleet programmatically. All requests are authenticated using API keys and rate-limited based on your configuration.

Key Features

  • RESTful API - Standard HTTP methods and JSON responses
  • API Key Authentication - Secure access with scoped permissions
  • Rate Limiting - Configurable limits per minute, hour, and day
  • Webhooks - Real-time event notifications with retry logic
  • Request Logging - Full audit trail of API usage

Base URL

https://app.levyelectric.com/api/partner/v1

Getting Started

Creating an API Key

1

Navigate to Integrations

Go to Dashboard → Settings → Integrations.

2

Click Create API Key

Click New API Key button.

3

Configure Key Settings

  • Enter a descriptive Name (e.g., "Production Integration")
  • Select Permissions for this key
  • Set Rate Limits if needed
  • Optionally set an Expiration Date
4

Save and Copy Key

Click Create and immediately copy the secret key.

Save Your Secret Key

The API key secret is only shown once at creation. Store it securely - if lost, you'll need to regenerate the key.

API Key Format

API keys use the format: lf_pk_<32 random characters>

Example: lf_pk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6

Only the first 12 characters (prefix) are stored for display. The full key is hashed using SHA-256 for secure storage.

Authentication

Request Headers

All API requests must include the API key header:

curl -X GET "https://app.levyelectric.com/api/partner/v1/vehicles" \
  -H "X-Partner-Api-Key: lf_pk_your_api_key_here" \
  -H "Content-Type: application/json"

Optional Headers

HeaderDescription
X-Subaccount-IdTarget a specific subaccount (for global keys)
Content-TypeAlways application/json

Authentication Errors

StatusCodeDescription
401UNAUTHORIZEDMissing or invalid API key
403FORBIDDENKey lacks required permission

Permissions

API keys are granted specific permissions that control what operations they can perform.

Available Permissions

PermissionDescription
vehicles:readList and view vehicles
vehicles:writeUpdate vehicle status
rides:readList and view rides
rides:writeStart, pause, resume, end rides
customers:readList and view customers
customers:writeBlock/unblock customers
wallet:readView customer wallet balance
wallet:writeCredit/debit customer wallets
zones:readList and view zones
pricing:readView pricing configuration
webhooks:readList and view webhooks
webhooks:writeCreate, update, delete webhooks

Default Permissions

New API keys receive read-only access by default:

  • vehicles:read
  • rides:read
  • customers:read
  • zones:read
  • pricing:read

Key Scopes

ScopeDescription
subaccountAccess limited to one subaccount
globalAccess to multiple subaccounts (specify in allowed_subaccount_ids)

Rate Limiting

API requests are rate-limited to prevent abuse and ensure fair usage.

Default Limits

WindowDefault Limit
Per Minute60 requests
Per Hour1,000 requests
Per Day10,000 requests

Response Headers

Rate limit status is included in response headers:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 2025-01-15T10:31:00Z

Rate Limit Exceeded

When limits are exceeded, you'll receive a 429 response:

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded for minute window. Retry after 2025-01-15T10:31:00Z",
    "details": {
      "limit": 60,
      "window": "minute",
      "retry_after": 45
    }
  },
  "meta": {
    "request_id": "req_abc123",
    "timestamp": "2025-01-15T10:30:15Z"
  }
}

API Endpoints

Vehicles

List Vehicles

GET /api/partner/v1/vehicles
GET /api/partner/v1/vehicles?status=available&limit=50

Get Vehicle

GET /api/partner/v1/vehicles/{id}

Update Vehicle Status

PATCH /api/partner/v1/vehicles/{id}
{
  "status": "maintenance"
}

Nearby Vehicles

GET /api/partner/v1/vehicles/nearby?lat=40.7128&lng=-74.0060&radius=500

Rides

List Rides

GET /api/partner/v1/rides
GET /api/partner/v1/rides?status=active

Get Ride

GET /api/partner/v1/rides/{id}

Start Ride (requires rides:write)

POST /api/partner/v1/rides
{
  "customer_id": "uuid",
  "vehicle_id": "uuid"
}

Pause Ride

POST /api/partner/v1/rides/{id}/pause

Resume Ride

POST /api/partner/v1/rides/{id}/resume

End Ride

POST /api/partner/v1/rides/{id}/end
{
  "end_latitude": 40.7128,
  "end_longitude": -74.0060
}

Customers

List Customers

GET /api/partner/v1/customers
GET /api/partner/v1/customers?email=user@example.com

Get Customer

GET /api/partner/v1/customers/{id}

Get Wallet Balance

GET /api/partner/v1/customers/{id}/wallet

Credit Wallet (requires wallet:write)

POST /api/partner/v1/customers/{id}/wallet
{
  "action": "credit",
  "amount_cents": 1000,
  "description": "Promotional credit"
}

Zones

List Zones

GET /api/partner/v1/zones
GET /api/partner/v1/zones?type=parking

Pricing

Get Pricing

GET /api/partner/v1/pricing

Response Format

Success Response

{
  "data": {
    "id": "uuid",
    "vehicle_number": "V001",
    "status": "available"
  },
  "meta": {
    "request_id": "req_abc123",
    "timestamp": "2025-01-15T10:30:00Z"
  }
}

List Response

{
  "data": [
    { "id": "uuid-1", "vehicle_number": "V001" },
    { "id": "uuid-2", "vehicle_number": "V002" }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 125,
    "has_next": true,
    "has_prev": false
  },
  "meta": {
    "request_id": "req_abc123",
    "timestamp": "2025-01-15T10:30:00Z"
  }
}

Error Response

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Vehicle not found",
    "details": {
      "vehicle_id": "uuid"
    }
  },
  "meta": {
    "request_id": "req_abc123",
    "timestamp": "2025-01-15T10:30:00Z"
  }
}

Webhooks

Webhooks send real-time HTTP POST requests to your server when events occur.

Setting Up Webhooks

1

Navigate to Webhooks

Go to Dashboard → Settings → Integrations → Webhooks.

2

Create Webhook

Click New Webhook.

3

Configure Endpoint

  • Enter your Webhook URL (HTTPS required)
  • Select Events to subscribe to
  • Add custom headers if needed
4

Save and Test

Save the webhook, then use Test to verify delivery.

Webhook Events

EventTrigger
ride.startedCustomer unlocks a vehicle
ride.endedRide completes
ride.pausedRide is paused
ride.resumedPaused ride resumes
customer.createdNew customer registers
customer.updatedCustomer profile updated
customer.blockedCustomer is blocked
customer.unblockedCustomer is unblocked
vehicle.status_changedVehicle status changes
vehicle.battery_lowBattery drops below threshold
vehicle.location_updatedVehicle moves significantly

Webhook Payload

{
  "event": "ride.ended",
  "event_id": "evt_abc123def456",
  "timestamp": "2025-01-15T10:30:00Z",
  "data": {
    "ride_id": "uuid",
    "customer_id": "uuid",
    "customer_number": 12345,
    "vehicle_id": "uuid",
    "vehicle_number": "V001",
    "start_time": "2025-01-15T10:00:00Z",
    "end_time": "2025-01-15T10:30:00Z",
    "duration_minutes": 30,
    "distance_km": 5.2,
    "pricing": {
      "total_cents": 850,
      "unlock_cents": 100,
      "time_cents": 750,
      "distance_cents": 0,
      "discount_cents": 0
    },
    "payment_status": "paid",
    "subaccount_id": "uuid"
  }
}

Webhook Signature

Webhooks are signed using HMAC-SHA256 for security verification.

Signature Header:

X-Levy-Signature: t=1705312200,v1=abc123...

Verification (Node.js example):

const crypto = require('crypto')

function verifyWebhook(payload, signature, secret) {
  const parts = signature.split(',')
  const timestamp = parts.find(p => p.startsWith('t=')).substring(2)
  const expectedSig = parts.find(p => p.startsWith('v1=')).substring(3)

  // Check timestamp is recent (within 5 minutes)
  const age = Math.floor(Date.now() / 1000) - parseInt(timestamp)
  if (age > 300) return false

  // Compute signature
  const signedPayload = `${timestamp}.${JSON.stringify(payload)}`
  const computedSig = crypto
    .createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex')

  return computedSig === expectedSig
}

Retry Logic

Failed webhook deliveries are automatically retried:

AttemptDelay
1Immediate
21 second
32 seconds
44 seconds
58 seconds

After 5 failed attempts, the delivery is marked as failed.

API Key Management

Regenerating Keys

If a key is compromised:

  1. Go to Settings → Integrations
  2. Find the API key
  3. Click Regenerate
  4. Update your systems with the new key
  5. The old key is immediately invalidated

Disabling Keys

Temporarily disable a key without deleting it:

  1. Find the API key
  2. Toggle Active to off
  3. All requests with this key will return 401

Viewing Usage

Monitor API key activity:

  • Last Used - When the key was last used
  • Requests Today - Count of today's requests
  • Requests This Week/Month - Historical usage

Best Practices

Security

  1. Store keys securely - Use environment variables, not code
  2. Use HTTPS - All API calls must use HTTPS
  3. Verify webhooks - Always validate webhook signatures
  4. Rotate keys - Regenerate keys periodically
  5. Minimum permissions - Only grant necessary permissions

Performance

  1. Use pagination - Request smaller pages for large lists
  2. Cache responses - Cache read-only data appropriately
  3. Handle rate limits - Implement exponential backoff
  4. Use webhooks - Prefer webhooks over polling

Error Handling

  1. Check response codes - Handle 4xx and 5xx errors
  2. Use request IDs - Log request_id for debugging
  3. Retry transient errors - Retry 5xx errors with backoff
  4. Monitor failures - Alert on repeated webhook failures

Troubleshooting

Authentication Failures

ErrorSolution
Missing headerAdd X-Partner-Api-Key header
Invalid keyVerify key is correct and active
Expired keyRegenerate or remove expiration
Wrong permissionsUpdate key permissions

Webhook Issues

IssueSolution
Not receiving eventsCheck webhook is active and URL is accessible
Signature verification failsVerify you're using the correct secret
Timeout errorsRespond to webhooks within 30 seconds
Missing eventsCheck you've subscribed to the event type

Rate Limit Issues

IssueSolution
Frequently hitting limitsImplement caching and reduce request frequency
Need higher limitsContact support to discuss limit increases
Burst usageSpread requests over time

SDK Examples

Node.js

const axios = require('axios')

const api = axios.create({
  baseURL: 'https://app.levyelectric.com/api/partner/v1',
  headers: {
    'X-Partner-Api-Key': process.env.LEVY_API_KEY,
    'Content-Type': 'application/json'
  }
})

// List available vehicles
const { data } = await api.get('/vehicles', {
  params: { status: 'available' }
})

console.log(data.data) // Array of vehicles

Python

import requests
import os

API_KEY = os.environ['LEVY_API_KEY']
BASE_URL = 'https://app.levyelectric.com/api/partner/v1'

headers = {
    'X-Partner-Api-Key': API_KEY,
    'Content-Type': 'application/json'
}

# Get a specific vehicle
response = requests.get(
    f'{BASE_URL}/vehicles/uuid-here',
    headers=headers
)

vehicle = response.json()['data']
print(f"Vehicle {vehicle['vehicle_number']}: {vehicle['status']}")

Ready to Integrate

With the Partner API, you can build powerful integrations that connect Levy Fleets with your existing systems. Start with read-only access, test thoroughly, then enable write permissions for production use.