# VectorCare Open API Developer Guide - Complete Content
This file contains the complete documentation for the VectorCare Open API.
Generated automatically from source markdown files.
---
# OPEN API 2.0
# Open API 2.0 Overview
:::caution[Open API 1.0 Retiring August 12, 2026]
Open API 1.0 will be retired on **August 12, 2026**. If you are currently integrated with Open API 1.0, please begin your Open API 2.0 integration as soon as possible. Open API 2.0 is a completely new integration approach, not an incremental upgrade, so plan accordingly. Contact [support@vectorcare.com](mailto:support@vectorcare.com) to get started.
:::
Open API 2.0 is a greatly simplified integration that uses webhooks as the primary method for receiving service request data. This represents a significant architectural shift from v1.0, providing real-time updates with a consistent, static data structure.
## What's Different from 1.0?
- **Webhook-driven architecture**: All trip data comes from webhooks rather than polling endpoints
- **Static data structure**: Unchanging field names for simpler mapping and maintenance
- **Simplified request status**: A new `request_status` field provides a clear view of where requests stand
- **Better standing order support**: Individual webhook messages for each request in a collection
- **Consolidated endpoints**: State and location updates use a single API URL
:::tip[Environment Selector]
Use the environment selector in the header to switch between UAT and Production. All URLs in the documentation will update automatically.
:::
## What's Available
### Receiving Webhooks
VectorCare pushes all service request data to your endpoint in real-time via webhooks. There are no polling endpoints in v2.0.
1. [Get started](/v2/setup/) with your VectorCare UAT environment
2. [Build your webhook endpoint](/v2/webhooks/overview/) to receive request data
3. [Verify webhook signatures](/v2/webhooks/verification/) to ensure authenticity
### Reporting Trip Progress
Most integrations also send data back to VectorCare:
- [**State Updates**](/v2/service-requests/state-update/) - Report trip milestones (en route, arrived, completed)
- [**Location Updates**](/v2/service-requests/location-update/) - Send GPS coordinates for live tracking
### Service Request Actions
These endpoints let you interact with service requests beyond reporting trip progress:
- [**Accept/Decline**](/v2/service-requests/accept-decline/) - Accept or decline service requests broadcast to your organization
- [**Best Time**](/v2/service-requests/best-time/) - Propose your best available time for a service request
- [**Change Request**](/v2/service-requests/change-request/) - Request a change to the agreed pickup time
- [**Create Request**](/v2/service-requests/create/) - Programmatically create service requests (requires coordination with VectorCare)
## Integration Support
We're here to help you with your Open API 2.0 integration. Reach out to [support@vectorcare.com](mailto:support@vectorcare.com) to get started, and we can:
- **Set up UAT access**: Get access to VectorCare's test environment for development and testing
- **Create a dedicated channel**: We'll spin up a Slack, Teams, or other channel for your team to communicate directly with us
- **Schedule a walkthrough**: We're happy to walk through the integration together on a call
## Plain Text Version
[View complete guide as plain text](/llms-full.txt)
---
# Getting Started
## Testing in UAT
VectorCare is a two-sided marketplace. **Requesters** (healthcare organizations) create service requests, and **Receivers** (transport service providers) fulfill them. As an integrator, it is most likely your system operates as a Receiver, but on UAT you will need to act in both roles to simulate production behavior.
To test the full webhook flow in UAT, you need access to both sides:
- A **Requester** organization to create and broadcast service requests
- A **Receiver** organization where your webhook and client credentials are configured
Contact [support@vectorcare.com](mailto:support@vectorcare.com) and we'll get your UAT environment set up with both organizations for you. We will handle permissions and user configuration on our end.
### Switching Between Organizations
Click the icon with nine boxes at the top of the page, next to your company name, to switch between your Requester and Receiver organizations. Make sure you verify which organization you're in before taking any actions.
### Configuring Your Receiver Organization
Your Receiver organization is where your integration lives. You will need to configure the following in your Receiver organization under **Settings** > **Open API**:
1. **Client Credentials**: Create credentials for [OAuth2 authentication](/v2/authentication/). Copy and securely store the Client Secret immediately as it will only be shown once.
2. **Webhook URL**: Enter your HTTPS endpoint where VectorCare will send webhook events. Select `v2.0` as the Webhook Version.
:::caution
Never commit client secrets to source control, expose them in client-side code, or send them over insecure channels. Treat them like passwords.
:::
### Triggering Webhook Events
1. Switch to your **Requester** organization
2. Create a new service request
3. On the detail page for the service request, click **Take Action** > **Broadcast**
4. Click **Show Other Service Providers** and select your Receiver organization
5. Your Receiver organization will get a webhook with `request_status: AVAILABLE` and `action: BROADCAST_RECEIVED`
6. Switch to your **Receiver** organization and accept the request from the VectorCare interface, or use the [Accept](/v2/service-requests/accept-decline/) endpoint
7. Your Receiver organization will get a second webhook with `request_status: ASSIGNED` and `action: BROADCAST_ACCEPTED`
### Webhook Call History
The **Webhook Call History** section in your Receiver organization's Open API settings shows recent webhook deliveries:
| Column | Description |
|---|---|
| Request ID | The service request that triggered the webhook |
| Webhook ID | Which webhook received the call |
| Response Code | HTTP status returned by your endpoint |
| Data | Click to view the full payload |
| Redeliver | Manually resend a failed webhook |
| Event Type | The action that triggered the webhook |
| Created | Timestamp of the delivery attempt |
Use this to debug integration issues and redeliver missed webhooks.
## Webhook Requirements
- Endpoint must use HTTPS (HTTP is rejected)
- Endpoint must respond within 10 seconds
- Endpoint must return a 2xx status code on success
- Maximum of 2 active webhooks per organization
- Each customer organization requires its own webhook URL configuration. A common pattern is to include an identifier in your webhook URL (e.g., `https://yoursite.com/webhook?customer_id=123`)
### IP Allowlist
VectorCare delivers webhooks from a fixed set of IP addresses. If your endpoint is behind a firewall or cloud security group, you will need to allow these IPs. See [Webhooks Overview: IP Allowlist](/v2/webhooks/overview/#ip-allowlist) for the full list and configuration guidance.
### RSA Public Key
The webhook configuration displays the RSA-SHA256 public key used to sign webhooks. Use this to [verify webhook signatures](/v2/webhooks/verification/).
:::note
The RSA public key is shared across all organizations and is currently the same between UAT and Production environments, though the keys can be rotated separately.
:::
## Client Credential Management
- Client credentials are specific to each organization. If you are an integrator working with multiple service providers, each will likely have their own organization, which means setting up a webhook and client credentials for each one.
- Credentials can be deleted if compromised or no longer needed
- Rotating credentials: Create a new credential, update your integration, then delete the old one
## CAD Configuration
The **CAD Name** field identifies your integration in VectorCare's internal systems. This is typically set during onboarding and doesn't affect API functionality. If you don't see your CAD listed, contact support@vectorcare.com and we'll add it for you.
## Permissions Reference
VectorCare will configure permissions for your organization during onboarding. For reference, these are the permissions required for Open API access:
| Permission | Description |
|---|---|
| **Can access Open API** | User can interact with Open API endpoints |
| **Can configure Open API Client Credentials** | User can create and delete Client Credentials for Open API integrations |
| **Can configure Open API for account** | User is allowed to generate credentials for Open API clients and configure webhook URLs |
| **Can configure Webhooks** | User can create and delete Webhook endpoints |
---
# Webhooks Overview
VectorCare sends real-time service request updates to your systems via webhooks. **Webhooks are the only way you can access service request data in Open API 2.0.**
When an event occurs in VectorCare, we send an HTTP POST request to your registered endpoint with a JSON payload containing the event details.
## How It Works
```
VectorCare Event → HTTP POST → Your Webhook Endpoint → Process & Respond 2xx
```
1. Something changes in VectorCare (new request, data update, status change)
2. VectorCare sends a POST request to your registered webhook URL
3. Your server processes the data and responds with a 2xx status code
4. If we don't receive a 2xx, we retry with exponential backoff
## Implementation Requirements
1. **Create a publicly accessible HTTPS endpoint**
2. **Allow inbound traffic from VectorCare's IP addresses** (see [IP Allowlist](#ip-allowlist) below)
3. **Register your endpoint URL** in the VectorCare dashboard
4. **Implement idempotency** using the `event_id` and `service_request_id` fields
5. **Return a 2xx status code** to acknowledge receipt
## Webhook Payload Fields
| Field | Type | Description |
|---|---|---|
| `event_id` | string | Unique identifier for deduplication (chronologically sortable) |
| `event_timestamp` | string | UTC timestamp when webhook was sent (ISO 8601) |
| `service_request_id` | string | Unique identifier for the service request |
| `request_status` | string | Simplified status: `AVAILABLE`, `ASSIGNED`, `COMPLETED`, or `UNAVAILABLE` |
| `action` | string | The event that triggered this webhook |
| `data` | object | Complete request details (null when status is `UNAVAILABLE`) |
## Setting Up Your Webhook
See [Configuring Your Receiver Organization](/v2/setup/#configuring-your-receiver-organization) in the Getting Started guide.
## Response Codes
| Your Response | Meaning | VectorCare Action |
|---------------|---------|-------------------|
| `2xx` | Success | Delivery complete |
| `4xx`, `5xx`, timeout | Failure | Retry with backoff |
Only `2xx` responses are considered successful. All other responses trigger retries.
## Retry Behavior
VectorCare retries failed webhooks with exponential backoff:
| Attempt | Delay |
|---------|-------|
| 1st (initial) | Immediate |
| 2nd | ~8 seconds |
| 3rd (final) | ~64 seconds |
Retries are triggered when your endpoint:
- Returns a non-2xx response
- Times out (>10 seconds)
- Is unreachable
After 3 failed attempts, the webhook is marked as failed. You can manually redeliver failed webhooks from the VectorCare dashboard.
## IP Allowlist
VectorCare delivers webhooks from the following IP addresses. If your endpoint is behind a firewall, WAF, or cloud security group, you must allow inbound HTTPS (port 443) traffic from all of them:
- `13.56.93.191`
- `13.56.34.202`
- `44.235.183.156`
- `44.237.187.110`
- `44.238.226.200`
- `3.137.97.122`
- `52.14.5.45`
- `3.143.153.56`
This applies to any layer that filters traffic before it reaches your application, including:
- Cloud provider firewall rules (AWS Security Groups, GCP firewall rules, Azure NSGs)
- Web application firewalls (AWS WAF, Cloudflare, etc.)
- CDN or reverse proxy allow lists
- OS-level firewalls (iptables, ufw)
:::tip
If your webhook endpoint is returning timeouts or connection errors in the [Webhook Call History](/v2/setup/#webhook-call-history), a firewall blocking VectorCare's IPs is one of the most common causes.
:::
## Quick Links
- [Payload Structure](/v2/webhooks/payload-structure/) - Full event payload schema
- [Request Status Values](/v2/webhooks/request-status/) - Understanding status states
- [Actions](/v2/webhooks/actions/) - Event types that trigger webhooks
- [Verification](/v2/webhooks/verification/) - Validating webhook signatures
- [Best Practices](/v2/webhooks/best-practices/) - Performance and reliability tips
---
# Webhook Payload Structure
import { Tabs, TabItem } from '@astrojs/starlight/components';
This page documents the complete structure of webhook payloads sent by VectorCare.
## Example Payloads
:::note[About These Examples]
The "All Fields" tab is a schema reference showing every possible field populated. The scenario tabs are **hypothetical examples** illustrating what payloads might look like for different transport types. They are not real payloads and should not be relied on as exact representations. The actual fields populated in your webhooks depend on how each healthcare organization configures their service forms and what the requester enters. In practice, many fields will be `null` when the organization has not mapped them or when no value was provided.
:::
A schema reference showing every field populated with example values. In practice, many of these fields will be `null` depending on the organization's configuration and the type of transport.
A hypothetical BLS ambulance transport moving an inpatient from a skilled nursing facility to a hospital for a CT scan. The patient is on contact isolation precautions. This request has not yet been accepted, so responder fields and `agreed_for_time` are `null`.
A hypothetical critical care transport between hospitals with IV therapy, oxygen, and cardiac monitoring. This request has been accepted, so it includes an `agreed_for_time`, responder details, and a `revised_eta`. Fields like `cct_criteria`, `intravenous_therapy`, `medical_supervision`, `medications`, `override_approver`, and `override_reason` are populated in this scenario.
A hypothetical recurring wheelchair transport for a dialysis patient picked up from home. This trip is part of a standing order collection and is the outbound leg of a round trip with a scheduled return time. The patient's son is accompanying as an additional passenger. Fields like `collection_id`, `is_dialysis_trip`, `pickup_is_home`, `additional_passenger_*`, and `travel_authorization_number` are populated in this scenario.
When a request is no longer available to your organization (e.g., the broadcast was canceled, expired, or declined), the `request_status` is `UNAVAILABLE` and the `data` field is `null`. Your webhook handler should check for this case before attempting to read `data` fields.
```json
{
"event_id": "b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4",
"event_timestamp": "2026-02-15T10:30:45.000Z",
"service_request_id": "VC-TN4KQ8R2",
"request_status": "UNAVAILABLE",
"action": "BROADCAST_CANCELED",
"data": null
}
```
---
## Top-Level Fields
| Field | Type | Nullable | Description |
|---|---|---|---|
| `event_id` | string | | Unique identifier for this webhook event. Chronologically sortable. IDs generated later are lexicographically greater. Use to deduplicate retried webhooks and determine event ordering. |
| `event_timestamp` | string | | When the webhook was sent (ISO 8601 UTC) |
| `service_request_id` | string | | Unique identifier for this service request (e.g., `VC-BSBBCY5Q`) |
| `request_status` | string | | High-level status indicator (see [Request Status](/v2/webhooks/request-status/)) |
| `action` | string | | What triggered this webhook (see [Actions](/v2/webhooks/actions/)) |
| `data` | object | nullable | Full request details (see [Data Object Fields](#data-object-fields) below). Null when `request_status` is `UNAVAILABLE`. |
---
## Data Object Fields
All fields are always present but many will be null depending on request state and service configuration. Healthcare organizations configure which fields are collected for their transport requests.
:::note[Organization-Configured Fields]
Many fields in the data object have values that are configured by each healthcare organization. Boolean fields (like `can_ambulate`, `has_own_wheelchair`, `is_inpatient`) are normalized to `true`/`false` regardless of how the organization labels them. These fields are nullable and return `null` when the field is not mapped to the organization's form or when no value was provided by the requester. Other fields like `destination_facility_type` or `required_equipment` may have values that differ between organizations.
:::
### Core Fields
| Field | Type | Nullable | Description |
|---|---|---|---|
| `service_request_id` | string | | Unique identifier for this service request (e.g., `VC-BSBBCY5Q`) |
| `request_current_state` | string | | Internal VectorCare workflow state (e.g., `awaiting`, `accepted`) |
| `change_request_enabled` | boolean | | Whether you can submit a [Change Request](/v2/service-requests/change-request/) to propose a new pickup time for this request |
| `service_type` | string | | Type of transport service (custom configured by requesting organization) |
| `service_level_type` | string | nullable | Medical service level (custom configured, e.g., ALS, BLS, CCT, Wheelchair) |
| `scheduling_option` | string | | How the pickup time was scheduled (e.g., `specific`, `asap`) |
| `scheduling_type` | string | | Trip direction: `one_way` or `round_trip` |
| `organization_id` | string | | Unique identifier for the requesting organization |
| `account_name` | string | | Display name of the organization that created the request |
| `facility_name` | string | nullable | Name of the specific facility within the organization |
| `collection_id` | string | nullable | Groups related trips together (e.g., standing orders) |
| `service_request_web_url` | string | | URL to view this service request in the VectorCare web application. The user following this link must be logged in to VectorCare (this is a web session login, not related to API credentials). |
### Timing
| Field | Type | Nullable | Description |
|---|---|---|---|
| `agreed_for_time` | string | nullable | Confirmed pickup time (ISO 8601 UTC). When present, this is the authoritative pickup time and may differ from `pickup_date_time`. `null` until both parties have agreed on the pickup time. Fall back to `pickup_date_time` when this field is `null`. |
| `pickup_date_time` | string | nullable | Originally requested pickup time (ISO 8601 UTC). This is **not** the confirmed pickup time. See the separate `agreed_for_time` field, which should be used as the authoritative pickup time when it is present. |
| `appointment_datetime` | string | nullable | Patient's appointment time at destination |
| `return_date_time` | string | nullable | Scheduled time for return trip pickup |
| `revised_eta` | string | nullable | Updated estimated time of arrival if changed from original |
### Locations
| Field | Type | Nullable | Description |
|---|---|---|---|
| `pickup_location` | location | nullable | Pickup address with GPS coordinates (see [Location Object](#location-object-structure)) |
| `pickup_facility_name` | string | nullable | Name of the facility at pickup location |
| `pickup_facility_type` | string | nullable | Category of the pickup facility (e.g., hospital, SNF) |
| `pickup_is_home` | boolean | nullable | Indicates if pickup location is the patient's residence |
| `pickup_exact_location` | string | nullable | Specific location within the facility (e.g., "ER Bay 3") |
| `pickup_room_number` | string | nullable | Room or bed number at the pickup location |
| `pickup_stair_steps` | string | nullable | Number of stair steps at pickup (for accessibility) |
| `pickup_phone_number` | string | nullable | Contact phone number for pickup location |
| `pickup_phone_number_extension` | string | nullable | Phone extension for pickup location |
| `destination_location` | location | nullable | Destination address with GPS coordinates (see [Location Object](#location-object-structure)) |
| `destination_facility_name` | string | nullable | Name of the facility at destination |
| `destination_facility_type` | string | nullable | Category of the destination facility |
| `destination_is_home` | boolean | nullable | Indicates if destination is the patient's residence |
| `destination_exact_location` | string | nullable | Specific location within the destination facility |
| `destination_address_detail` | string | nullable | Additional address info (unit number, suite, building) |
| `destination_room_number` | string | nullable | Room or bed number at destination |
| `destination_stair_steps` | string | nullable | Number of stair steps at destination |
| `destination_phone_number` | string | nullable | Contact phone number for destination |
| `destination_phone_number_extension` | string | nullable | Phone extension for destination |
| `departure_airport` | location | nullable | Departure airport, air transport only (see [Location Object](#location-object-structure)) |
| `arrival_airport` | location | nullable | Arrival airport, air transport only (see [Location Object](#location-object-structure)) |
### Patient Information
| Field | Type | Nullable | Description |
|---|---|---|---|
| `patient_id` | string | nullable | VectorCare patient identifier |
| `patient_first_name` | string | nullable | Patient's first name |
| `patient_middle_name` | string | nullable | Patient's middle name |
| `patient_last_name` | string | nullable | Patient's last name |
| `patient_date_of_birth` | string | nullable | Patient's date of birth in `YYYY-MM-DD` format |
| `patient_age` | number | nullable | Patient's age in years |
| `patient_gender` | string | nullable | Patient's gender |
| `patient_weight_lbs` | number | nullable | Patient's weight in pounds |
| `patient_weight_kg` | number | nullable | Patient's weight in kilograms |
| `patient_height_inches` | number | nullable | Patient's height in inches |
| `patient_girth_inches` | number | nullable | Patient's girth measurement in inches |
| `patient_bmi` | string | nullable | Patient's body mass index |
| `patient_over_300p` | boolean | nullable | Indicates if patient weighs over 300 lbs (bariatric) |
| `patient_language_spoken` | string | nullable | Patient's preferred spoken language |
| `patient_language_written` | string | nullable | Patient's preferred written language |
| `patient_interpreter_required` | boolean | nullable | Indicates if an interpreter is needed for the transport |
| `patient_membership_primary_id` | string | nullable | Primary member ID or medical record number (MRN) |
| `patient_membership_primary_prefix` | string | nullable | Prefix for the primary member ID |
| `patient_membership_secondary_id` | string | nullable | Secondary member ID or MRN |
| `patient_membership_secondary_prefix` | string | nullable | Prefix for the secondary member ID |
| `patient_active_membership` | boolean | nullable | Indicates if patient has an active membership |
| `patient_coverages` | array | nullable | Patient's insurance coverage information |
### Medical
| Field | Type | Nullable | Description |
|---|---|---|---|
| `diagnosis_notes` | string | nullable | Clinical notes or diagnosis information |
| `can_ambulate` | boolean | nullable | Indicates if patient can walk independently |
| `patient_is_ready` | boolean | nullable | Indicates if patient is ready for pickup |
| `is_inpatient` | boolean | nullable | Indicates if patient is currently admitted |
| `is_dialysis_trip` | boolean | nullable | Indicates if transport is for dialysis treatment |
| `is_recent_onset` | boolean | nullable | Indicates if patient's condition is recent onset |
| `hospice` | boolean | nullable | Indicates if patient is under hospice care |
| `o2` | string | nullable | Oxygen flow rate in liters per minute |
| `intravenous_therapy` | array | nullable | IV therapy details and requirements |
| `number_of_drips` | string | nullable | Number of active IV drips during transport |
| `medications` | array | nullable | Medications being administered during transport |
| `cct_criteria` | array | nullable | Criteria met for critical care transport level |
| `medical_supervision` | array | nullable | Required medical supervision level |
| `mental_health_hold` | array | nullable | Mental health hold status (e.g., 5150) |
| `isolation_precaution` | boolean | nullable | General isolation precaution flag |
| `under_isolation` | array | nullable | Specific isolation types required (e.g., contact, airborne) |
### Equipment
| Field | Type | Nullable | Description |
|---|---|---|---|
| `has_own_wheelchair` | boolean | nullable | Indicates if patient will bring their own wheelchair |
| `required_equipment` | array | nullable | Medical equipment needed for transport |
| `special_equipment` | array | nullable | Additional specialized equipment requirements |
### People
| Field | Type | Nullable | Description |
|---|---|---|---|
| `requester_first_name` | string | | First name of the person who created the request |
| `requester_last_name` | string | | Last name of the person who created the request |
| `requester_email` | string | | Email address of the requester |
| `requester_phone_number` | string | nullable | Phone number of the requester |
| `requester_phone_number_extension` | string | nullable | Phone extension for the requester |
| `responder_user_first_name` | string | nullable | First name of the assigned transport provider user |
| `responder_user_last_name` | string | nullable | Last name of the assigned transport provider user |
| `responder_user_email` | string | nullable | Email of the assigned transport provider user |
| `contact_name` | string | nullable | Name of alternate contact person for this transport |
| `contact_phone` | string | nullable | Phone number of alternate contact |
| `additional_passenger_name` | string | nullable | Name of person accompanying the patient |
| `additional_passenger_phone` | string | nullable | Phone number of accompanying person |
| `additional_passenger_relationship` | string | nullable | Accompanying person's relationship to patient |
| `additional_passenger_weight` | string | nullable | Weight of accompanying person in pounds |
| `additional_personnel` | array | nullable | Additional crew or staff requirements |
| `authorizing_physician` | string | nullable | Physician who authorized the transport |
| `receiving_practitioner` | string | nullable | Practitioner receiving the patient at destination |
| `receiving_practitioner_2` | string | nullable | Additional practitioner receiving the patient |
| `transporting_practitioner` | string | nullable | Practitioner accompanying patient during transport |
### Request Details
| Field | Type | Nullable | Description |
|---|---|---|---|
| `trip_priority_level` | string | nullable | Urgency level assigned to the request |
| `escalated` | boolean | nullable | Indicates if the request has been escalated |
| `note` | string | nullable | Free-text notes added by the requester |
| `transport_reason` | array | nullable | Selected reasons for the transport |
| `other_requirements` | string | nullable | Free-text field for additional transport requirements |
### Payment & Authorization
| Field | Type | Nullable | Description |
|---|---|---|---|
| `payment_option_primary` | string | nullable | Primary payer or insurance provider |
| `payment_option_primary_group_number` | string | nullable | Group number for primary insurance |
| `payment_option_primary_subscriber_id` | string | nullable | Subscriber ID for primary insurance |
| `payment_plan_primary` | string | nullable | Payment plan for primary payer |
| `payment_option_secondary` | string | nullable | Secondary payer or insurance provider |
| `payment_option_secondary_group_number` | string | nullable | Group number for secondary insurance |
| `payment_option_secondary_subscriber_id` | string | nullable | Subscriber ID for secondary insurance |
| `payment_plan_secondary` | string | nullable | Payment plan for secondary payer |
| `pre_authorization_number` | string | nullable | Insurance pre-authorization number |
| `external_authorization` | string | nullable | External system authorization reference |
| `travel_authorization_number` | string | nullable | Travel-specific authorization number |
| `gl_code` | string | nullable | General ledger code for billing |
| `case_number` | string | nullable | External case or reference number |
### Round Trip & Return
| Field | Type | Nullable | Description |
|---|---|---|---|
| `is_round_trip_first_trip` | boolean | | True if this request is the outbound leg of a round trip |
| `is_round_trip_return_trip` | boolean | | True if this request is the return leg of a round trip |
| `round_trip_other_service_request_id` | string | nullable | Service request ID of the linked trip leg |
| `wait_and_return` | boolean | nullable | Indicates if crew should wait at destination for return |
| `return_on_will_call` | boolean | nullable | Indicates if return trip is on will-call |
### Override & Dry Run
| Field | Type | Nullable | Description |
|---|---|---|---|
| `override_approver` | string | nullable | Name of person who approved a service level override |
| `override_reason` | array | nullable | Reasons provided for the service level override |
| `dry_run_reason` | array | nullable | Reasons for dry run (crew arrived but patient was not transported) |
---
## Location Object Structure
All location fields share this structure:
| Field | Type | Nullable | Description |
|---|---|---|---|
| `address` | string | nullable | Full formatted address string |
| `city` | string | nullable | City name |
| `country` | string | nullable | Country name |
| `lat` | number | nullable | GPS latitude coordinate |
| `lng` | number | nullable | GPS longitude coordinate |
| `name` | string | nullable | Location display name or facility name |
| `state` | string | nullable | State or province abbreviation |
| `street` | string | nullable | Street address line |
| `zip` | string | nullable | ZIP or postal code |
---
# Request Status Values
The `request_status` field provides a simplified view of where a service request stands in relation to your integration. This is separate from the internal VectorCare state (`request_current_state`).
For many integrations, `request_status` is all you need to drive your workflow. The [`action`](/v2/webhooks/actions/) field is available for integrations that need more granular detail about what triggered the webhook.
## Status Values
| Status | Description |
|---|---|
| `AVAILABLE` | Request exists but is not yet officially assigned to your organization |
| `ASSIGNED` | Request is officially assigned to you and you have responsibility for it |
| `COMPLETED` | Request has been fulfilled according to service criteria |
| `UNAVAILABLE` | Request is no longer accessible (canceled, withdrawn, or inactive) |
## Status Details
### `AVAILABLE`
The request has been broadcast to your organization but you haven't accepted it yet.
**What to do:**
- You may want to wait before creating the trip in your system
- Use the [Accept endpoint](/v2/service-requests/accept-decline/) to claim the request
- Or use the [Decline endpoint](/v2/service-requests/accept-decline/) to pass on it
:::note
In many cases, you might not want requests in your system until they reach `ASSIGNED` status.
:::
### `ASSIGNED`
The request is officially yours to fulfill. This happens when:
- You accepted a broadcast
- The requester directly assigned the trip to you
- Your proposal was accepted
**What to do:**
- Create the trip in your system
- Begin dispatching/scheduling
- Send [state updates](/v2/service-requests/state-update/) as the trip progresses
### `COMPLETED`
The trip has been marked complete in VectorCare. The service was delivered according to the defined criteria.
**What to do:**
- Update your records to reflect completion
- No further state updates needed
### `UNAVAILABLE`
The request is no longer accessible to your organization. This can happen when:
- The request was canceled by the requester (all providers receive `UNAVAILABLE`)
- Another provider accepted the broadcast (you receive `UNAVAILABLE`)
- The broadcast expired without a response
- The request was reassigned to another provider
**What to do:**
- Remove or cancel the trip in your system
- Note: The `data` field will be `null` in this case
:::note
When a request is canceled, all providers who received the broadcast will receive an `UNAVAILABLE` webhook. Similarly, when one provider accepts a broadcast, all other providers will receive `UNAVAILABLE`.
:::
**Example `UNAVAILABLE` payload:**
```json
{
"event_id": "xyz789abcdef",
"event_timestamp": "2025-05-09T02:30:00Z",
"service_request_id": "KP-ABCD1234",
"request_status": "UNAVAILABLE",
"action": "BROADCAST_CANCELED",
"data": null
}
```
## Example Payloads
### `AVAILABLE` Request
```json
{
"event_id": "abc123",
"service_request_id": "KP-ABCD1234",
"request_status": "AVAILABLE",
"action": "BROADCAST_RECEIVED",
"data": {
"patient_first_name": "John",
"patient_last_name": "Doe",
// ... full data object
}
}
```
### `UNAVAILABLE` Request
```json
{
"event_id": "xyz789",
"service_request_id": "KP-ABCD1234",
"request_status": "UNAVAILABLE",
"action": "BROADCAST_CANCELED",
"data": null
}
```
## Status vs. Action
The `request_status` tells you the **current state** of the request relative to your organization.
The `action` tells you **what happened** to trigger this webhook.
For example:
- `request_status: ASSIGNED` + `action: BROADCAST_ACCEPTED` = You just accepted the request
- `request_status: ASSIGNED` + `action: REQUEST_DATA_UPDATED` = The request data changed (still assigned to you)
See [Actions](/v2/webhooks/actions/) for the full list of action values.
---
# Webhook Actions
The `action` field indicates what event triggered the webhook. This helps you understand why you received the notification and what changed.
Many integrations can rely solely on [`request_status`](/v2/webhooks/request-status/) to drive their logic (e.g., create a trip when `AVAILABLE`, update when `ASSIGNED`, remove when `UNAVAILABLE`). The `action` field provides additional context for integrations that need to handle specific events differently, but it is not required for most workflows.
## Action Values
### Broadcast Actions
| Action | Description |
|---|---|
| `BROADCAST_RECEIVED` | A new broadcast was sent inviting you to accept the request |
| `BROADCAST_ACCEPTED` | You successfully accepted the broadcast and are now assigned |
| `BROADCAST_DECLINED` | You declined the broadcast - request no longer available to you |
| `BROADCAST_CANCELED` | The broadcast was canceled by the requester before you responded |
| `BROADCAST_EXPIRED` | The broadcast expired without a response from you |
### Proposal Actions
| Action | Description |
|---|---|
| `PROPOSAL_SUBMITTED` | You submitted a proposal - awaiting requester review |
| `PROPOSAL_ACCEPTED` | Your proposal was accepted - you are now assigned |
| `PROPOSAL_DECLINED` | Your proposal was declined by the requester |
### Change Request Actions
| Action | Description |
|---|---|
| `CHANGE_REQUEST_ACCEPTED` | Your change request was approved - agreed time updated to your proposed time |
| `CHANGE_REQUEST_DECLINED` | Your change request was declined - original agreed time remains |
### Data Actions
| Action | Description |
|---|---|
| `REQUEST_DATA_UPDATED` | Request data was modified (times, locations, patient info, etc.) |
## Action by Status
Here's how actions typically map to request status:
| Action | Typical request_status |
|---|---|
| `BROADCAST_RECEIVED` | `AVAILABLE` |
| `BROADCAST_ACCEPTED` | `ASSIGNED` |
| `BROADCAST_DECLINED` | `UNAVAILABLE` |
| `BROADCAST_CANCELED` | `UNAVAILABLE` |
| `BROADCAST_EXPIRED` | `UNAVAILABLE` |
| `PROPOSAL_SUBMITTED` | `AVAILABLE` |
| `PROPOSAL_ACCEPTED` | `ASSIGNED` |
| `PROPOSAL_DECLINED` | `UNAVAILABLE` |
| `CHANGE_REQUEST_ACCEPTED` | `ASSIGNED` |
| `CHANGE_REQUEST_DECLINED` | `ASSIGNED` |
| `REQUEST_DATA_UPDATED` | Varies (usually `ASSIGNED` or `AVAILABLE`) |
## Common Scenarios
### New Trip Available
```json
{
"action": "BROADCAST_RECEIVED",
"request_status": "AVAILABLE",
"service_request_id": "KP-ABCD1234"
}
```
A new request was broadcast to you. Review and decide whether to accept or decline.
### Trip Assigned to You
```json
{
"action": "BROADCAST_ACCEPTED",
"request_status": "ASSIGNED",
"service_request_id": "KP-ABCD1234"
}
```
You accepted the broadcast (or the requester assigned it directly). Create the trip in your system.
### Trip Details Changed
```json
{
"action": "REQUEST_DATA_UPDATED",
"request_status": "ASSIGNED",
"service_request_id": "KP-ABCD1234"
}
```
Something changed on a trip you're assigned to. Compare the `data` object with your records and update accordingly. Common changes include:
- Pickup/appointment times
- Addresses
- Patient information
- Special requirements
### Trip No Longer Available
```json
{
"action": "BROADCAST_CANCELED",
"request_status": "UNAVAILABLE",
"service_request_id": "KP-ABCD1234"
}
```
The request was canceled or withdrawn. Remove it from your pending queue.
## Handling `REQUEST_DATA_UPDATED`
The `REQUEST_DATA_UPDATED` action is the most common webhook you'll receive. It fires whenever any field on the request changes.
Any field can change after a request is assigned, including pickup times, locations, and patient information. The only fields guaranteed to remain constant are the identifiers (`service_request_id`, `organization_id`, etc.).
**Best practice:** Replace your stored data entirely with the new payload rather than comparing field-by-field. The `data` object always contains the complete current state of the request.
---
# Webhook Verification
Verify that webhooks are genuinely from VectorCare and haven't been tampered with. All webhook payloads are signed using RSA-SHA256.
## How It Works
1. VectorCare signs the webhook body with a private key
2. The signature is included in the `X-VectorCare-Signature` header (base64-encoded)
3. You verify the signature using VectorCare's public key
4. If verification fails, reject the webhook
## Getting the Public Key
1. Log into VectorCare as an organization admin
2. Navigate to **Settings** > **Open API**
3. Copy the RSA public key (PEM format)
## Verification Details
| Property | Value |
|----------|-------|
| Algorithm | RSA with SHA-256 |
| Padding | PKCS#1 v1.5 |
| Signature encoding | Base64 |
| Data to verify | Raw request body (bytes) |
The signature must be verified against the raw request body bytes before any JSON parsing.
## Python (Flask)
Using [PyCryptodome](https://pycryptodome.readthedocs.io/) (`pip install pycryptodome`):
```python
from base64 import b64decode
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from flask import Flask, request, abort
app = Flask(__name__)
# In production, load from environment variable or secrets manager
PUBLIC_KEY = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...
-----END PUBLIC KEY-----"""
def verify_signature(public_key: str, signature: str, data: bytes) -> bool:
try:
rsakey = RSA.importKey(public_key)
verifier = PKCS1_v1_5.new(rsakey)
digest = SHA256.new()
digest.update(data)
return verifier.verify(digest, b64decode(signature))
except (ValueError, TypeError):
return False
@app.route("/webhook", methods=["POST"])
def webhook():
signature = request.headers.get("X-VectorCare-Signature")
if not signature or not verify_signature(PUBLIC_KEY, signature, request.data):
abort(401)
data = request.get_json()
# Process webhook...
return "", 200
```
## Node.js (Express)
Using the built-in `crypto` module:
```javascript
const crypto = require('crypto');
const express = require('express');
const app = express();
// In production, load from environment variable or secrets manager
const PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...
-----END PUBLIC KEY-----`;
function verifySignature(publicKey, signature, data) {
try {
const verifier = crypto.createVerify('RSA-SHA256');
verifier.update(data);
return verifier.verify(publicKey, signature, 'base64');
} catch (error) {
return false;
}
}
// Use raw body parser to get bytes before JSON parsing
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-vectorcare-signature'];
if (!signature || !verifySignature(PUBLIC_KEY, signature, req.body)) {
return res.status(401).send('Invalid signature');
}
const data = JSON.parse(req.body);
// Process webhook...
res.status(200).send();
});
```
## Go (net/http)
Using the standard library:
```go
package main
import (
"crypto"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"io"
"log"
"net/http"
)
// In production, load from environment variable or secrets manager
const publicKey = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...
-----END PUBLIC KEY-----`
func verifySignature(publicKeyPEM string, signature string, data []byte) error {
block, _ := pem.Decode([]byte(publicKeyPEM))
if block == nil {
return errors.New("failed to parse PEM block")
}
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return err
}
rsaPub, ok := pub.(*rsa.PublicKey)
if !ok {
return errors.New("not an RSA public key")
}
sigBytes, err := base64.StdEncoding.DecodeString(signature)
if err != nil {
return err
}
hash := sha256.Sum256(data)
return rsa.VerifyPKCS1v15(rsaPub, crypto.SHA256, hash[:], sigBytes)
}
func webhookHandler(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Failed to read body", http.StatusBadRequest)
return
}
signature := r.Header.Get("X-VectorCare-Signature")
if err := verifySignature(publicKey, signature, body); err != nil {
http.Error(w, "Invalid signature", http.StatusUnauthorized)
return
}
// Process webhook...
w.WriteHeader(http.StatusOK)
}
func main() {
http.HandleFunc("/webhook", webhookHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
```
## Important Notes
1. **Verify before processing** - Always verify the signature before trusting the data
2. **Use raw bytes** - Verify against the raw request body, not parsed/re-serialized JSON
3. **Reject failures** - Return `401` and don't process webhooks with invalid signatures
4. **Store keys securely** - Don't hardcode keys in source code; use environment variables or a secrets manager
---
# Best Practices
Build a robust integration by following these patterns.
## Use a Queue
VectorCare sends webhooks in real-time, which means:
- Multiple webhooks can arrive in rapid succession
- A single transport may generate 10+ webhooks over its lifecycle
- Bursts of activity (shift changes, batch updates) create spikes
**Don't process webhooks synchronously.** Instead:
1. Receive the webhook
2. Verify the signature
3. Push to your queue
4. Return `200` immediately
5. Process from the queue asynchronously
This ensures fast responses (our fastest integrators respond in under 1 second), absorbs traffic spikes, and lets you retry failed processing without losing data.
## Prevent Duplicates and Handle Ordering
Webhooks can arrive out of order, and VectorCare may retry failed deliveries. Use timestamp-based upserts to handle both:
```sql
CREATE TABLE service_requests (
id SERIAL PRIMARY KEY,
external_id VARCHAR(50) UNIQUE NOT NULL, -- service_request_id
last_updated TIMESTAMP NOT NULL,
data JSONB
);
-- Only apply updates when event_timestamp is newer
INSERT INTO service_requests (external_id, last_updated, data)
VALUES ('KP-ABCD1234', '2025-01-15T14:30:00Z', '...')
ON CONFLICT (external_id) DO UPDATE
SET last_updated = EXCLUDED.last_updated,
data = EXCLUDED.data
WHERE service_requests.last_updated < EXCLUDED.last_updated;
```
Don't rely on application-level checks before inserting. This leads to race conditions when processing concurrent webhooks.
:::tip
Each webhook contains the complete current state. If you process a newer event first, you can safely skip older ones.
:::
## Handle Errors Gracefully
When sending state or location updates to VectorCare, handle failures appropriately:
**Timestamp validation**: Timestamps must be within 7 days of the current time and cannot be in the future. If a state update is rejected for timestamp reasons, don't retry indefinitely - the timestamp will only get more stale.
**Rate limiting**: If you receive a `429` response, back off before retrying. Implement exponential backoff to avoid making the problem worse.
**Network failures**: Queue failed requests for retry, but set a reasonable limit. A state update from 3 days ago may no longer be relevant.
**Don't block on failures**: If a state update fails, continue processing other requests. One problematic request shouldn't halt your entire integration.
See [Error Codes](/v2/error-codes/) for the complete list of error responses.
## Debug with Webhook History
VectorCare maintains a log of all webhook deliveries in the admin interface. Use this to:
- Verify webhooks are being sent
- Check delivery status and response codes
- Resend failed webhooks manually
- Inspect payload contents
If you suspect missing data, check the webhook history before assuming a bug in your integration.
---
# Authentication
VectorCare implements the [OAuth2](https://oauth.net/2/) protocol for authenticating applications. You must obtain an access token before making API requests.
POSThttps://auth.vectorcare.com/v2.0/oauth2/token
## Request
Send a `POST` request with form-data body:
| Field | Value | Description |
|---|---|---|
| `client_id` | Your client ID | Generated in VectorCare Open API settings |
| `client_secret` | Your client secret | Generated in VectorCare Open API settings |
| `grant_type` | `client_credentials` | Always use this value |
### Example Request
```bash
curl -X POST https://auth.vectorcare.com/v2.0/oauth2/token \
-d "client_id=your_client_id" \
-d "client_secret=your_client_secret" \
-d "grant_type=client_credentials"
```
## Response
### Success (200 OK)
```json
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...",
"token_type": "bearer",
"expires_in": 3600
}
```
| Field | Type | Description |
|---|---|---|
| `access_token` | string | JWT token for API requests |
| `token_type` | string | Always `bearer` |
| `expires_in` | integer | Token lifetime in seconds (typically 3600) |
### Error (401 Unauthorized)
```json
{
"error_description": "Client authentication failed.",
"error": "invalid_client"
}
```
## Using the Token
Include the token in the `Authorization` header for all API requests:
```bash
curl -X POST https://hub.vectorcare.com/openapi/v2.0/requests/KP-ABCD1234/state/ \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..." \
-H "Content-Type: application/json" \
-d '{"name": "en_route", "timestamp": "2025-01-15T14:30:00Z"}'
```
## Token Refresh
The `expires_in` field indicates when the token will expire (typically 1 hour). **Proactively refresh your token before expiration** to avoid `401 Unauthorized` errors.
Recommended approach:
1. Store the token and its expiration time
2. Request a new token when ~80% of the lifetime has elapsed
3. Retry failed requests with a fresh token if you receive a 401
:::tip[Best Practice]
Don't wait for a 401 error to refresh. Set a timer based on `expires_in` and refresh proactively.
:::
## Generating Credentials
1. Log into VectorCare as an organization admin
2. Navigate to **Settings** → **Open API**
3. Click **Generate Credentials**
4. Store your `client_id` and `client_secret` securely
:::caution[Security]
Never expose your `client_secret` in client-side code, logs, or version control. Treat it like a password.
:::
---
# State Update
Use this endpoint to report trip progress timestamps to VectorCare.
Note: URLs must include the trailing slash.
## How It Works
This endpoint records **when** specific events occurred during a trip. You provide a state name and the timestamp when that state happened.
:::note[Important]
This does not directly change the status of the service request in VectorCare. Instead, it logs timestamps for a predefined set of transport states. The service request's actual status is managed separately by VectorCare based on the overall workflow.
One exception: service creators can configure an "autocomplete" state (such as `arrived` or `on_board`) that will mark the request as completed when you send that specific state. For example, if a service creator sets their autocomplete state to `arrived`, then posting the `arrived` state will immediately mark the request as completed (even before `completed` is sent). This is configured per-service and is not the default behavior.
:::
## Request Body
```json
{
"name": "en_route",
"timestamp": "2025-01-15T14:30:00Z"
}
```
| Field | Type | Description |
|---|---|---|
| `name` | string | State value (see table below) |
| `timestamp` | string | ISO 8601 UTC timestamp when the state occurred |
## Available States
| State | Value | Description |
|---|---|---|
| En Route | `en_route` | En route to pickup location |
| Arrived | `arrived` | Arrived at pickup location |
| On Board | `on_board` | Patient on board at pickup location |
| Arrived at Destination | `arrived_at_destination` | Arrived at destination |
| Completed | `completed` | Trip complete |
| Canceled | `canceled` | Trip canceled (any reason) |
| Dry Run | `dry_run` | Trip canceled at pickup location |
## State Flow
A typical trip progresses through states in order:
```
en_route → arrived → on_board → arrived_at_destination → completed
```
However, any trip can also end with:
- `canceled` - Trip canceled before completion
- `dry_run` - Trip canceled after arriving at pickup (patient not available, etc.)
## Example
```bash
curl -X POST "https://hub.vectorcare.com/openapi/v2.0/requests/KP-ABCD1234/state/" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..." \
-H "Content-Type: application/json" \
-d '{
"name": "en_route",
"timestamp": "2025-01-15T14:30:00Z"
}'
```
### Success (201 Created)
```json
{
"name": "en_route",
"timestamp": "2025-01-15T14:30:00Z"
}
```
## Timestamp Rules
- Must be in ISO 8601 format with UTC timezone (e.g., `2025-01-15T14:30:00Z`)
- Cannot be in the future
- Must be within 7 days of the current time
:::tip
Always use the actual time the event occurred, not the time you're sending the request.
:::
## Errors
| Status | Cause |
|---|---|
| 400 | Invalid state name, timestamp in future, or timestamp too old |
| 401 | Invalid or expired token |
| 404 | Request not found |
---
# Location Update
Use this endpoint to send GPS location updates during a trip.
Note: URLs must include the trailing slash.
## Request Body
Send an array of location objects (max 200 per request):
```json
[
{
"lat": 37.8577747,
"lng": -122.49209,
"alt": 20.23,
"speed": 10.3,
"timestamp": 1575497090.131
},
{
"lat": 37.8578123,
"lng": -122.49198,
"alt": 20.45,
"speed": 12.1,
"timestamp": 1575497095.456
}
]
```
| Field | Type | Description |
|---|---|---|
| `lat` | number | Latitude |
| `lng` | number | Longitude |
| `alt` | number | Altitude in meters |
| `speed` | number | Speed (optional) |
| `timestamp` | number | Unix epoch timestamp in seconds |
## Example Request
```bash
curl -X POST "https://hub.vectorcare.com/openapi/v2.0/requests/KP-ABCD1234/locations/" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..." \
-H "Content-Type: application/json" \
-d '[
{
"lat": 37.8577747,
"lng": -122.49209,
"alt": 20.23,
"speed": 10.3,
"timestamp": 1575497090.131
}
]'
```
## Responses
### Success (200 OK)
```json
{}
```
An empty object indicates success.
### Missing Required Fields (400 Bad Request)
```json
[
{
"timestamp": [
{
"message": "This field is required.",
"code": "common:required"
}
],
"lat": [
{
"message": "This field is required.",
"code": "common:required"
}
],
"lng": [
{
"message": "This field is required.",
"code": "common:required"
}
],
"alt": [
{
"message": "This field is required.",
"code": "common:required"
}
]
}
]
```
## Batching Locations
You can send up to **200 location objects** in a single request. This is useful for:
- Sending historical location data
- Batch uploading after connectivity issues
- Reducing API call frequency
```json
[
{"lat": 37.857, "lng": -122.492, "alt": 20, "timestamp": 1575497090.0},
{"lat": 37.858, "lng": -122.491, "alt": 21, "timestamp": 1575497095.0},
{"lat": 37.859, "lng": -122.490, "alt": 22, "timestamp": 1575497100.0}
// ... up to 200 total
]
```
## Timestamp Format
The timestamp is a **Unix epoch timestamp in seconds** as a floating-point number:
```
1575497090.131
│ │
│ └── Milliseconds (optional)
└──────────── Seconds since Jan 1, 1970 UTC
```
Convert from ISO 8601 to Unix timestamp in your language of choice.
## Best Practices
### Send locations periodically
- During active transport, send locations every 10-30 seconds
- Batch multiple points if your system collects them faster
### Handle offline scenarios
If connectivity is lost:
1. Store locations locally
2. Batch upload when connectivity returns
3. Ensure timestamps reflect when locations were recorded, not uploaded
### Validate before sending
- Ensure coordinates are valid (lat: -90 to 90, lng: -180 to 180)
- Verify altitude is reasonable for your region
- Confirm timestamps are not in the future
:::tip
Location updates help VectorCare track trip progress and provide ETAs. More frequent updates during active transport improve accuracy.
:::
---
# Accept & Decline
Use these endpoints to accept or decline service requests that have been broadcast to your organization.
## Accept Request
### Request Body
```json
{
"response_notes": "No available units in that area at this time."
}
```
| Field | Type | Description |
|---|---|---|
| `response_notes` | string | Optional notes explaining the decline (max 450 characters) |
### Example
```bash
curl -X PUT "https://hub.vectorcare.com/openapi/v2.0/requests/KP-ABCD1234/decline/" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..." \
-H "Content-Type: application/json" \
-d '{
"response_notes": "Outside service area."
}'
```
### Success Response (201 Created)
```json
{}
```
## What Happens Next
| Action | Webhook You'll Receive | Request Status |
|---|---|---|
| Accept | `BROADCAST_ACCEPTED` | `ASSIGNED` |
| Decline | `BROADCAST_DECLINED` | `UNAVAILABLE` |
| No response | `BROADCAST_EXPIRED` | `UNAVAILABLE` |
After accepting, begin dispatching and sending [state updates](/v2/service-requests/state-update/) and [location updates](/v2/service-requests/location-update/).
## Error Handling
| Status | Cause | Resolution |
|---|---|---|
| 401 | Invalid/expired token | Refresh your access token |
| 403 | Request not available to you | May already be assigned or canceled |
| 404 | Request not found | Verify the `request_id` |
| 400 | Invalid request body | Check `response_notes` length |
---
# Best Time
Use this endpoint to propose your best available time for a service request.
## Request Body
```json
{
"proposed_agreed_dt": "2025-01-15T15:30:00Z"
}
```
| Field | Type | Description |
|---|---|---|
| `proposed_agreed_dt` | string | Proposed pickup time (ISO 8601 UTC) |
## Example Request
```bash
curl -X PUT "https://hub.vectorcare.com/openapi/v2.0/requests/KP-ABCD1234/best-time/" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..." \
-H "Content-Type: application/json" \
-d '{
"proposed_agreed_dt": "2025-01-15T15:30:00Z"
}'
```
## Response
### Success (201 Created)
```json
{}
```
An empty object indicates your proposed time was submitted successfully.
## When to Use
Use this endpoint when:
- You've received a broadcast request
- You can fulfill the request but at a different time than originally requested
- You want to propose an alternative pickup time for consideration
The requester will be notified of your proposed time and can:
- Accept your proposed time
- Counter with a different time
- Assign the request to another provider
## Flow
```
1. Receive BROADCAST_RECEIVED webhook
2. Review the requested pickup time
3. If you can do it at a different time, POST to /best-time/
4. Wait for response (via webhook)
- PROPOSAL_ACCEPTED → You're assigned at your proposed time
- PROPOSAL_DECLINED → Request may go to another provider
```
:::note
Submitting a best time is a proposal, not an acceptance. The requester must approve your proposed time before you're assigned to the request.
:::
---
# Change Request
Use this endpoint to propose a change to the agreed pickup time after you have accepted a request. The request creator will receive a change request notification and can approve or decline your proposed change.
:::caution[Check availability first]
Not all service requests support change requests. Check the `change_request_enabled` field in the [webhook payload](/v2/webhooks/payload-structure/#core-fields) before calling this endpoint.
:::
## Request Body
```json
{
"agreed_dt": "2025-01-15T15:30:00Z",
"change_reason": "Traffic"
}
```
| Field | Type | Description |
|---|---|---|
| `agreed_dt` | string | Proposed new pickup time (ISO 8601 UTC) |
| `change_reason` | string | Reason for the change request (max 450 characters) |
### Common Change Reasons
The following are common reasons used when requesting a time change:
- Equipment Issues
- Inappropriate Level of Service
- Specialty Personnel Issue
- Traffic
- Wrong Address
- Staffing Issues
- HUB Request
- Site Request
- Responded to 911 call
- No Rigs Available
- Prior Calls
- Change in Availability
- Stat Urgent
- No Reason Given
- Dry Run
## Example Request
```bash
curl -X POST "https://hub.vectorcare.com/openapi/v2.0/requests/KP-ABCD1234/change-request/" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..." \
-H "Content-Type: application/json" \
-d '{
"agreed_dt": "2025-01-15T15:30:00Z",
"change_reason": "Traffic"
}'
```
## Response
### Success (200 OK)
```json
{}
```
An empty object indicates your change request was submitted successfully.
## When to Use
Use this endpoint when:
- You have already accepted a request
- You need to change the agreed pickup time
- You want the request creator to approve the new time
The request creator will be notified of your proposed change and can:
- Approve your proposed time
- Decline your proposed time
## Flow
```
1. Accept a request via /accept/ endpoint
2. Circumstances change and you need a different pickup time
3. POST to /change-request/ with new time and reason
4. Request creator receives notification
5. Wait for webhook response:
- Approved → CHANGE_REQUEST_ACCEPTED with new agreed_for_time
- Declined → CHANGE_REQUEST_DECLINED (original time remains)
```
## Webhook Responses
When the request creator responds to your change request, you'll receive a webhook:
| Outcome | Action | What Changed |
|---|---|---|
| Approved | `CHANGE_REQUEST_ACCEPTED` | `agreed_for_time` updated to your proposed time |
| Declined | `CHANGE_REQUEST_DECLINED` | Nothing - original agreed time remains |
:::note
This endpoint is only available for accepted providers. If you are responding to a broadcast request and want to propose a different time, use the [Best Time](/v2/service-requests/best-time) endpoint instead.
:::
---
# Create Service Request
The Create Service Request endpoint allows you to programmatically create new service requests in VectorCare.
:::caution[Contact Us First]
This feature **requires coordination with the VectorCare team** before you can use it. Please reach out at **support@vectorcare.com** to get started.
:::
## How It Works
Each service in VectorCare defines its own request schema, the set of fields required to create a request for that service. Because schemas vary by service, there is no single fixed request body. Instead, VectorCare provides **interactive API documentation** that shows the exact request body structure for each service available to your organization.
When you open the interactive docs, you'll see each service listed with its service ID, name, and the full request body schema including all required and optional fields.
## Example
The interactive docs will show you one or more services, each with their own endpoint and request body. Here's an example of what a simple service might look like. The service ID (`2JV3RG9K` in this example) is unique to each service and will be shown in the interactive documentation.
### Request Body
The request body varies by service. A simple service might look like this:
```json
{
"patient": {
"id": "string",
"last_name": "string",
"first_name": "string"
},
"request": {
"test": "string"
}
}
```
Other services may require additional fields such as pickup/dropoff addresses, appointment times, insurance information, or custom fields specific to that service. The interactive documentation shows the complete schema for each service, including which fields are required and which are optional.
### Example Request
```bash
curl -X POST "https://hub.vectorcare.com/openapi/v2.0/requests/service/2JV3RG9K/" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..." \
-H "Content-Type: application/json" \
-d '{
"patient": {
"id": "PAT-001",
"last_name": "Smith",
"first_name": "John"
},
"request": {
"test": "value"
}
}'
```
### Success (201 Created)
```json
{
"request_id": "KP-ABCD1234",
"service_request_web_url": "https://hub.vectorcare.com/service_request/o/X5318RVM/permalink/KP-ABCD1234/"
}
```
The `service_request_web_url` is a permalink to view this request in the VectorCare web application. The user following this link must be logged in to VectorCare with their web session credentials (this is not related to API client credentials).
## Errors
| Status | Cause |
|---|---|
| 400 | Invalid request body or missing required fields |
| 401 | Missing, invalid, or expired token |
| 403 | Organization does not have permission to create requests for this service |
| 404 | Service ID not found or invalid schema version |
| 406 | Unsupported API version |
| 429 | Rate limit exceeded |
---
# Error Codes
This page documents the error responses returned by the VectorCare Open API.
## HTTP Status Codes
| Status | Description |
|---|---|
| `200 OK` | Request successful |
| `201 Created` | Resource created successfully |
| `400 Bad Request` | Invalid request body or parameters |
| `401 Unauthorized` | Missing or invalid authentication |
| `403 Forbidden` | Valid authentication but insufficient permissions |
| `404 Not Found` | Resource not found |
| `429 Too Many Requests` | Rate limit exceeded |
## Error Response Format
Error responses include a message and error code:
```json
{
"field_name": [
{
"message": "Human readable error message",
"code": "namespace:error_code"
}
]
}
```
For non-field errors:
```json
{
"message": "Human readable error message",
"code": "namespace:error_code"
}
```
## Common Error Codes
### Authentication Errors
| Code | Message |
|---|---|
| `members:not_authenticated` | Authentication credentials were not provided. |
| `members:authentication_failed` | Authentication failed. |
| `members:permission_denied` | You do not have permission to perform this action. |
### Validation Errors
| Code | Message |
|---|---|
| `common:required` | This field is required. |
| `common:null` | This field may not be null. |
| `common:blank` | This field may not be blank. |
| `common:choice_invalid` | "{input}" is not a valid choice. |
| `common:max_length` | Ensure this field has no more than {max_length} characters. |
| `common:integer_invalid` | A valid integer is required. |
| `common:number_invalid` | A valid number is required. |
| `common:email_invalid` | A valid email address is required. |
| `common:datetime_invalid_format` | Datetime format should be {format}. |
| `common:date_invalid_format` | Date format should be {format}. |
| `common:list_invalid` | Value should be a list. |
| `common:address_invalid` | Address is invalid. |
### API Errors
| Code | Message |
|---|---|
| `api:bad_request` | Bad request. |
| `api:not_found` | Not found. |
| `api:too_many_requests` | Request was throttled. |
| `api:method_not_allowed` | Method not allowed. |
| `api:unknown_error` | Unknown error. |
### Open API Specific Errors
| Code | Message |
|---|---|
| `public_api:public_api_not_enabled` | The Open API is not enabled for the service type of this request. |
| `responder:too_many_locations` | Too many locations. (Max 200 per request) |
## Example Error Responses
### `401` Unauthorized
```json
{
"message": "Authentication credentials were not provided.",
"code": "members:not_authenticated"
}
```
### `400` Bad Request (Validation Error)
```json
{
"name": [
{
"message": "\"invalid_state\" is not a valid choice.",
"code": "common:choice_invalid"
}
]
}
```
### `400` Bad Request (Timestamp Error)
```json
{
"timestamp": [
{
"message": "Timestamp cannot be in the future.",
"code": "api:bad_request"
}
]
}
```
### `403` Forbidden
```json
{
"message": "You do not have permission to perform this action.",
"code": "members:permission_denied"
}
```
### `429` Too Many Requests
```json
{
"message": "Request was throttled.",
"code": "api:too_many_requests"
}
```
## Rate Limiting
The API implements rate limiting to ensure service stability. If you exceed the rate limit, you'll receive a `429` Too Many Requests response.
When rate limited:
- Wait before retrying
- Implement exponential backoff
If you're consistently hitting rate limits, contact us to discuss your use case.
---
# Changelog
This page tracks changes to the Open API 2.0, including new fields, deprecated fields, and other updates.
## 2026
### March 2026
**New Fields (3/25/2026)**
- `service_request_web_url` - URL to view the service request in the VectorCare web application. Included in webhook payloads and the create request response. The user following this link must be logged in to VectorCare.
**Improvement (3/1/2026)**
- 13 fields now return `boolean` values (`true`/`false`/`null`) instead of organization-configured strings: `can_ambulate`, `destination_is_home`, `escalated`, `has_own_wheelchair`, `hospice`, `is_dialysis_trip`, `is_inpatient`, `is_recent_onset`, `isolation_precaution`, `patient_is_ready`, `pickup_is_home`, `return_on_will_call`, `wait_and_return`. A `null` value means the field is either not configured for the organization or no value was provided by the requester.
### February 2026
**Improvement (2/20/2026)**
- `event_id` is now chronologically sortable. IDs generated later are lexicographically greater, so you can compare event IDs to determine ordering
**New Webhook Actions (2/13/2026)**
- `CHANGE_REQUEST_ACCEPTED` - Sent when your change request is approved by the request creator
- `CHANGE_REQUEST_DECLINED` - Sent when your change request is declined by the request creator
**New Fields (2/12/2026)**
- `change_request_enabled` - Whether you can submit a change request for this request
**New Endpoint (2/11/2026)**
- [Change Request](/v2/service-requests/change-request/) - Propose a different pickup time after accepting a request
**Announcement (2/11/2026)**
- **Open API 1.0 is retiring on August 12, 2026.** After this date, all 1.0 endpoints and webhooks will no longer be available. Open API 2.0 is a completely new integration approach with webhook-driven architecture, a unified API URL, static payload structure, and new endpoints. Contact [support@vectorcare.com](mailto:support@vectorcare.com) if you need assistance with your Open API 2.0 integration.
### January 2026
**New Fields (1/28/2026)**
- `round_trip_other_service_request_id` - Identifier for the other leg of a round trip
**New Fields (1/19/2026)**
- `additional_passenger_name` - Name of additional passenger traveling with patient
- `additional_passenger_phone` - Phone number of additional passenger
- `additional_passenger_relationship` - Relationship of additional passenger to patient
- `additional_passenger_weight` - Weight of additional passenger in pounds
- `additional_personnel` - Additional personnel requirements for transport
- `destination_exact_location` - Specific location details at destination
- `destination_is_home` - Whether destination is patient's home address
- `dry_run_reason` - Reason transport was unsuccessful
- `escalated` - Whether request has been escalated
- `hospice` - Whether patient is under hospice care
- `is_inpatient` - Whether patient is currently admitted as inpatient
- `is_recent_onset` - Whether condition is recent onset
- `patient_is_ready` - Whether patient is ready for pickup
- `payment_plan_primary` - Primary payment plan type
- `payment_plan_secondary` - Secondary payment plan type
- `pickup_exact_location` - Specific location details at pickup
- `pickup_is_home` - Whether pickup is patient's home address
- `receiving_practitioner_2` - Secondary receiving practitioner
- `transporting_practitioner` - Name of transporting practitioner
---
## 2025
### December 2025
**New Endpoints (12/15/2025)**
- [Best Time](/v2/service-requests/best-time/) - Propose an alternative pickup time for a broadcast request
**New Endpoints (12/9/2025)**
- [Accept & Decline](/v2/service-requests/accept-decline/) - Accept or decline broadcast service requests
**New Fields (12/12/2025)**
- `action` - Event type that triggered the webhook (top-level field)
### August 2025
**New Fields (8/28/2025)**
- `contact_name` - Contact person's name
- `contact_phone` - Contact phone number
- `external_authorization` - External authorization number
- `is_dialysis_trip` - Whether this is a dialysis transport
- `note` - General transport notes
- `other_requirements` - Additional transport requirements
- `patient_bmi` - Patient's body mass index
- `payment_option_primary_group_number` - Primary insurance group number
- `payment_option_primary_subscriber_id` - Primary insurance subscriber ID
- `payment_option_secondary_group_number` - Secondary insurance group number
- `payment_option_secondary_subscriber_id` - Secondary insurance subscriber ID
- `return_date_time` - Return trip date and time
- `transport_reason` - Reasons for transport
- `trip_priority_level` - Priority level of the trip
### May 2025
**Initial Release (5/19/2025)**
Open API 2.0 launched with webhook-driven architecture.
**Top-Level Fields**
- `event_id`, `event_timestamp`, `service_request_id`, `request_status`, `data`
**Core Request Fields**
- `service_request_id`, `request_current_state`, `service_type`, `service_level_type`, `scheduling_option`, `scheduling_type`
**Organization Fields**
- `account_name`, `organization_id`, `facility_name`, `collection_id`
**Patient Fields**
- `patient_id`, `patient_first_name`, `patient_middle_name`, `patient_last_name`, `patient_date_of_birth`, `patient_age`, `patient_gender`, `patient_weight_lbs`, `patient_weight_kg`, `patient_height_inches`, `patient_girth_inches`, `patient_over_300p`, `patient_language_spoken`, `patient_language_written`, `patient_interpreter_required`, `patient_active_membership`, `patient_coverages`
**Membership Fields**
- `patient_membership_primary_id`, `patient_membership_primary_prefix`, `patient_membership_secondary_id`, `patient_membership_secondary_prefix`
**Location Fields**
- `pickup_location`, `destination_location` (with `address`, `city`, `country`, `lat`, `lng`, `name`, `state`, `street`, `zip`)
- `pickup_facility_name`, `pickup_facility_type`, `pickup_phone_number`, `pickup_phone_number_extension`, `pickup_room_number`, `pickup_stair_steps`
- `destination_facility_name`, `destination_facility_type`, `destination_phone_number`, `destination_phone_number_extension`, `destination_room_number`, `destination_stair_steps`, `destination_address_detail`
**Scheduling Fields**
- `pickup_date_time`, `agreed_for_time`, `appointment_datetime`, `revised_eta`
**Round Trip Fields**
- `is_round_trip_first_trip`, `is_round_trip_return_trip`, `return_on_will_call`, `wait_and_return`
**Personnel Fields**
- `requester_email`, `requester_first_name`, `requester_last_name`, `requester_phone_number`, `requester_phone_number_extension`
- `responder_user_email`, `responder_user_first_name`, `responder_user_last_name`
- `authorizing_physician`, `receiving_practitioner`
**Medical Fields**
- `diagnosis_notes`, `can_ambulate`, `cct_criteria`, `medications`, `intravenous_therapy`, `medical_supervision`, `mental_health_hold`, `o2`, `number_of_drips`
**Equipment Fields**
- `required_equipment`, `special_equipment`, `has_own_wheelchair`, `isolation_precaution`, `under_isolation`
**Payment Fields**
- `payment_option_primary`, `payment_option_secondary`, `pre_authorization_number`
**Administrative Fields**
- `case_number`, `gl_code`, `travel_authorization_number`, `override_approver`, `override_reason`
**Airport Fields**
- `departure_airport`, `arrival_airport`
---
## Deprecation Policy
Fields are rarely removed, but when deprecated:
1. Field will be marked as deprecated in this changelog
2. Field will continue to be sent for a transition period
3. Advance notice will be provided before removal
---
# OPEN API 1.0 (LEGACY)
# Open API 1.0 Overview
:::danger[Retiring August 12, 2026]
Open API 1.0 will be retired on **August 12, 2026**. After this date, all 1.0 endpoints and webhooks will no longer be available. Open API 2.0 is a completely new integration approach. See the [Open API 2.0 documentation](/v2/overview/) to get started.
:::
Open API 1.0 uses a polling-based architecture where you fetch service request data from VectorCare endpoints and receive notifications via webhooks.
## Key Differences from 2.0
| Feature | v1.0 | v2.0 |
|---|---|---|
| Data retrieval | Polling (GET endpoints) | Webhooks only |
| Data structure | Dynamic (configurable fields) | Static (fixed fields) |
| Endpoints | Multiple read endpoints | Webhook + update endpoints |
| Standing orders | Bulk webhook | Individual webhooks per request |
:::tip[Environment Selector]
Use the environment selector in the header to switch between environments. All URLs in the documentation will update automatically.
:::
## Requirements
1. VectorCare account with API feature enabled
2. Admin group with these permissions:
- `Can access Open API`
- `Can configure Open API Client Credentials`
- `Can configure Open API for account`
- `Can configure Webhooks`
See [About Group Permissions](https://vectorcare.zendesk.com/hc/en-us/articles/360047240353-About-Group-Permissions) for configuration details.
## Available Endpoints
### Read Operations
- [Request List (Partial)](/v1/requests-read/request-list/) - Get list of request IDs and basic info
- [Request List (Full)](/v1/requests-read/request-list-full/) - Get paginated list with full details
- [Request Detail](/v1/requests-read/request-detail/) - Get complete details for a single request
### Update Operations
- [State Update](/v1/requests-update/state-update/) - Post trip state changes
- [Location Update](/v1/requests-update/location-update/) - Post GPS coordinates
### Create Operations
- [Create Request](/v1/requests-create/) - Create new service requests
### Account Operations
- [Account Details](/v1/accounts/) - Get account information
### Webhooks
- [Webhook Messages](/v1/webhooks/) - Receive real-time notifications
## Getting Started
1. [Set up authentication](/v1/authentication/) to obtain access tokens
2. Use the [Request List](/v1/requests-read/request-list/) endpoint to discover available requests
3. Fetch full details with [Request Detail](/v1/requests-read/request-detail/)
4. Send updates via [State Update](/v1/requests-update/state-update/) and [Location Update](/v1/requests-update/location-update/)
5. Configure [webhooks](/v1/webhooks/) to receive real-time notifications
---
# Authentication
:::danger[Retiring August 12, 2026]
Open API 1.0 will be retired on **August 12, 2026**. After this date, all 1.0 endpoints and webhooks will no longer be available. Open API 2.0 is a completely new integration approach. See the [Open API 2.0 documentation](/v2/overview/) to get started.
:::
VectorCare implements the [OAuth2](https://oauth.net/2/) protocol for authenticating applications.
POSThttps://auth.vectorcare.com/v2.0/oauth2/token
## Request
Send a `POST` request with form-data body:
| Field | Value | Description |
|---|---|---|
| `client_id` | Your client ID | Generated in VectorCare Open API settings |
| `client_secret` | Your client secret | Generated in VectorCare Open API settings |
| `grant_type` | `client_credentials` | Always use this value |
## Response
### Success (200 OK)
```json
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...",
"token_type": "bearer",
"expires_in": 3600
}
```
| Field | Type | Description |
|---|---|---|
| `access_token` | string | JWT token for API requests |
| `token_type` | string | Always `bearer` |
| `expires_in` | integer | Token lifetime in seconds (typically 3600) |
### Error (401 Unauthorized)
```json
{
"error_description": "Client authentication failed.",
"error": "invalid_client"
}
```
## Using the Token
Include the token in the `Authorization` header for all API requests:
```
Authorization: Bearer {access_token}
```
## Token Refresh
Tokens expire after `expires_in` seconds (typically 1 hour). Proactively refresh before expiration to avoid `401 Unauthorized` errors.
## Generating Credentials
1. Log into VectorCare as an account admin
2. Navigate to **Settings** → **Open API**
3. Click **Generate Credentials**
4. Store your `client_id` and `client_secret` securely
See [VectorCare Open API Setup](https://vectorcare.zendesk.com/hc/en-us/articles/360048527193) for detailed instructions.
---
# Request List (Partial Details)
:::danger[Retiring August 12, 2026]
Open API 1.0 will be retired on **August 12, 2026**. After this date, all 1.0 endpoints and webhooks will no longer be available. Open API 2.0 is a completely new integration approach. See the [Open API 2.0 documentation](/v2/overview/) to get started.
:::
Returns a list of partial request details matching your query criteria.
Note: URLs must include the trailing slash.
## Query Parameters
| Parameter | Type | Description |
|---|---|---|
| `date__gte` | integer | Unix epoch timestamp, filter requests on or after this time. Default: Now - 24h |
| `date__lte` | integer | Unix epoch timestamp, filter requests on or before this time. Default: Now + 24h |
| `request__state` | string | Filter by state: `accepted`, `completed`, `canceled`. Default: `accepted` |
## Response
### Success (200 OK)
```json
[
{
"id": "ETMBWYYD",
"state": "accepted",
"created_timestamp_utc": "2021-01-11T22:19:01Z",
"event_dt_utc": "2021-01-13T19:00:00Z",
"last_updated_timestamp_utc": "2021-01-13T18:48:55Z"
},
{
"id": "ABC12345",
"state": "accepted",
"created_timestamp_utc": "2021-01-12T10:30:00Z",
"event_dt_utc": "2021-01-14T08:00:00Z",
"last_updated_timestamp_utc": "2021-01-13T15:22:10Z"
}
]
```
### Response Fields
| Field | Type | Description |
|---|---|---|
| `id` | string | VectorCare's unique request ID |
| `state` | string | Current state of the request |
| `created_timestamp_utc` | string | When the request was created (ISO 8601 UTC) |
| `event_dt_utc` | string | Event datetime based on: Agreed Time > Requested Time > Created Time |
| `last_updated_timestamp_utc` | string | Last modification time (ISO 8601 UTC) |
Results are returned in ascending order by `event_dt_utc`.
### Error (401 Unauthorized)
```json
{
"message": "Authentication credentials were not provided.",
"code": "members:not_authenticated"
}
```
## Usage Pattern
1. Call this endpoint to get a list of request IDs
2. Use the [Request Detail](/v1/requests-read/request-detail/) endpoint to fetch full details for each ID
3. Store the `last_updated_timestamp_utc` to detect changes on subsequent polls
:::tip
For full request details in a single call, use the [Request List (Full Details)](/v1/requests-read/request-list-full/) endpoint instead.
:::
---
# Request List (Full Details)
:::danger[Retiring August 12, 2026]
Open API 1.0 will be retired on **August 12, 2026**. After this date, all 1.0 endpoints and webhooks will no longer be available. Open API 2.0 is a completely new integration approach. See the [Open API 2.0 documentation](/v2/overview/) to get started.
:::
Returns a paginated list of requests with full details.
Note: URLs must include the trailing slash.
## Query Parameters
| Parameter | Type | Description |
|---|---|---|
| `date__gte` | integer | Unix epoch timestamp, filter requests on or after. Default: Now - 24h |
| `date__lte` | integer | Unix epoch timestamp, filter requests on or before. Default: Now + 24h |
| `request__state` | string | Filter by state: `awaiting`, `accepted`, `completed`, `canceled`. Default: `accepted` |
| `page` | integer | Page number for pagination. Default: `1` |
## Response
### Success (200 OK)
```json
{
"page": 1,
"pages": 3,
"results": [
{
"request_id": "EE5A6YZL",
"patient_first_name": "Angela",
"patient_last_name": "Graves",
"patient_dob": "1931-03-31",
"pickup_location": {
"lat": 37.8623,
"lng": -122.4911,
"zip": "94965",
"city": "Sausalito",
"name": "28 Liberty Ship Way",
"state": "CA",
"street": "28 Liberty Ship Way",
"address": "28 Liberty Ship Way, Sausalito, California 94965, United States",
"country": "United States"
},
"destination_location": {
"lat": 37.80119,
"lng": -122.43935,
"zip": "94123",
"city": "San Francisco",
"name": "96 Toledo Way",
"state": "CA",
"street": "96 Toledo Way",
"address": "96 Toledo Way, San Francisco, California 94123, United States",
"country": "United States"
},
"transport_pickup_time": "2022-04-28T14:00:00Z",
"transport_agreed_for_time": "2022-04-28T14:00:00Z",
"service_level_type": "BLS",
"service_type": "standing_order_dispatcher",
"account": {
"id": "2UVAGY7O",
"name": "Cool Company",
"service_levels": ["ALS", "BLS", "CCT", "WC"],
"facilities": null
},
"facility": {
"id": "2UVAGY7O",
"name": "Helpful Hospital #0"
},
"user": {
"first_name": "Nicole",
"last_name": "Montoya",
"email": "requester@example.com"
},
"enabled_patient_fields": {
"gender": "m"
},
"enabled_request_fields": {},
"request_current_state": "accepted",
"is_round_trip_first_trip": false,
"is_round_trip_return_trip": false,
"collection_id": "2UVAGY7O"
}
]
}
```
### Pagination Fields
| Field | Type | Description |
|---|---|---|
| `page` | number | Current page number |
| `pages` | number | Total number of pages |
| `results` | array | Array of request objects |
### Request Fields
See [Request Detail](/v1/requests-read/request-detail/) for full field descriptions.
### Error (401 Unauthorized)
```json
{
"message": "Authentication credentials were not provided.",
"code": "members:not_authenticated"
}
```
## Pagination
Use the `page` and `pages` fields to iterate through all results. Results are returned in descending order by `event_dt_utc`.
---
# Request Detail
:::danger[Retiring August 12, 2026]
Open API 1.0 will be retired on **August 12, 2026**. After this date, all 1.0 endpoints and webhooks will no longer be available. Open API 2.0 is a completely new integration approach. See the [Open API 2.0 documentation](/v2/overview/) to get started.
:::
Returns all details for a specific service request.
Note: URLs must include the trailing slash.
## Query Parameters
| Parameter | Type | Description |
|---|---|---|
| `exclude_facilities` | boolean | If `true`, omit `account.facilities` from response. Default: `false` |
## Response
### Success (200 OK)
```json
{
"request_id": "EE5A6YZL",
"patient_first_name": "Angela",
"patient_last_name": "Graves",
"patient_dob": "1931-03-31",
"pickup_location": {
"id": "address.2900060502936820",
"lat": 37.8623,
"lng": -122.4911,
"zip": "94965",
"city": "Sausalito",
"name": "28 Liberty Ship Way",
"state": "CA",
"street": "28 Liberty Ship Way",
"address": "28 Liberty Ship Way, Sausalito, California 94965, United States",
"country": "United States"
},
"destination_location": {
"id": "address.6571326868700452",
"lat": 37.80119,
"lng": -122.43935,
"zip": "94123",
"city": "San Francisco",
"name": "96 Toledo Way",
"state": "CA",
"street": "96 Toledo Way",
"address": "96 Toledo Way, San Francisco, California 94123, United States",
"country": "United States"
},
"transport_pickup_time": "2022-04-28T14:00:00Z",
"transport_agreed_for_time": "2022-04-28T14:00:00Z",
"service_level_type": "BLS",
"service_type": "standing_order_dispatcher",
"account": {
"id": "2UVAGY7O",
"name": "Cool Company",
"service_levels": ["ALS", "Ambulatory Van", "BLS", "CCT", "WC"],
"facilities": null
},
"facility": {
"id": "2UVAGY7O",
"name": "Helpful Hospital #0"
},
"user": {
"first_name": "Nicole",
"last_name": "Montoya",
"email": "requester@example.com"
},
"enabled_patient_fields": {
"gender": "m"
},
"enabled_request_fields": {},
"request_current_state": "accepted",
"is_round_trip_first_trip": false,
"is_round_trip_return_trip": false,
"collection_id": "2UVAGY7O"
}
```
## Primary Fields
These fields are standard for all requests:
| Field | Type | Description |
|---|---|---|
| `request_id` | string | Unique request identifier |
| `patient_first_name` | string | Patient's first name |
| `patient_last_name` | string | Patient's last name |
| `patient_dob` | string | Patient's date of birth |
| `pickup_location` | object | Pickup address (see Location Object) |
| `destination_location` | object | Destination address (see Location Object) |
| `transport_pickup_time` | string | Originally requested pickup time. Use `transport_agreed_for_time` as the authoritative pickup time when it is present. |
| `transport_agreed_for_time` | string | Confirmed pickup time. When present, this is the authoritative pickup time and may differ from `transport_pickup_time`. `null` until both parties have agreed on the pickup time. |
| `service_level_type` | string | Service level (ALS, BLS, CCT, etc.) |
| `service_type` | string | Service type name |
| `account` | object | Account that created the request |
| `facility` | object | Origin facility |
| `user` | object | User who accepted the request |
| `request_current_state` | string | Internal VectorCare state |
| `is_round_trip_first_trip` | boolean | Is this the first leg of a round trip? |
| `is_round_trip_return_trip` | boolean | Is this the return leg? |
| `collection_id` | string | ID for grouped requests (standing orders, round trips) |
## Location Object
| Field | Type | Description |
|---|---|---|
| `id` | string | Location identifier. Nullable |
| `lat` | number | Latitude. Nullable |
| `lng` | number | Longitude. Nullable |
| `zip` | string | ZIP code. Nullable |
| `city` | string | City. Nullable |
| `name` | string | Raw address string. Nullable |
| `state` | string | State. Nullable |
| `street` | string | Street address. Nullable |
| `address` | string | Full formatted address. Nullable |
| `country` | string | Country. Nullable |
:::note
Address fields may be null. We cannot guarantee all address components will have values.
:::
## Account Object
| Field | Type | Description |
|---|---|---|
| `id` | string | Account ID |
| `name` | string | Account name |
| `service_levels` | array | List of configured service levels |
| `facilities` | array | List of facilities (null if `exclude_facilities=true`). Nullable |
## Dynamic Fields
The `enabled_patient_fields` and `enabled_request_fields` objects contain configurable fields that vary by service. **Treat all fields in these objects as nullable.**
## Error Responses
### Request Not Found (403 Forbidden)
```json
{
"message": "You do not have permission to perform this action.",
"code": "members:permission_denied"
}
```
### Unauthorized (401)
```json
{
"message": "Authentication credentials were not provided.",
"code": "members:not_authenticated"
}
```
---
# State Update
:::danger[Retiring August 12, 2026]
Open API 1.0 will be retired on **August 12, 2026**. After this date, all 1.0 endpoints and webhooks will no longer be available. Open API 2.0 is a completely new integration approach. See the [Open API 2.0 documentation](/v2/overview/) to get started.
:::
Use this endpoint to report trip progress to VectorCare.
Note: URLs must include the trailing slash.
## Request Body
```json
{
"name": "en_route",
"timestamp": "2025-01-15T14:30:00Z"
}
```
| Field | Type | Description |
|---|---|---|
| `name` | string | State value (see table below) |
| `timestamp` | string | ISO 8601 UTC timestamp |
## Available States
| State Name | Value | Description |
|---|---|---|
| En Route | `en_route` | En route to pickup location |
| Arrived | `arrived` | Arrived at pickup location |
| On Board | `on_board` | Patient on board |
| Arrived at Destination | `arrived_at_destination` | Arrived at destination |
| Completed | `completed` | Trip complete |
| Canceled | `canceled` | Trip canceled |
| Dry Run | `dry_run` | Trip canceled at pickup |
## Responses
### Success (201 Created)
```json
{
"name": "en_route",
"timestamp": "2025-01-15T14:30:00Z"
}
```
### Invalid State (400)
```json
{
"name": [{"message": "\"invalid_state\" is not a valid choice.", "code": "common:choice_invalid"}]
}
```
### Invalid Timestamp (400)
Timestamp must be within 7 days of current time and not in the future.
## Timestamp Rules
- ISO 8601 format with UTC timezone
- Cannot be in the future
- Must be within 7 days of current time
---
# Location Update
:::danger[Retiring August 12, 2026]
Open API 1.0 will be retired on **August 12, 2026**. After this date, all 1.0 endpoints and webhooks will no longer be available. Open API 2.0 is a completely new integration approach. See the [Open API 2.0 documentation](/v2/overview/) to get started.
:::
Use this endpoint to send GPS location updates during a trip.
Note: URLs must include the trailing slash.
## Request Body
Send an array of location objects (max 200 per request):
```json
[
{
"lat": 37.8577747,
"lng": -122.49209,
"alt": 20.23,
"speed": 10.3,
"timestamp": 1575497090.131
}
]
```
| Field | Type | Description |
|---|---|---|
| `lat` | number | Latitude |
| `lng` | number | Longitude |
| `alt` | number | Altitude in meters |
| `speed` | number | Speed (optional) |
| `timestamp` | number | Unix epoch timestamp (seconds, float) |
## Responses
### Success (200 OK)
```json
{}
```
### Missing Fields (400)
```json
[
{
"lat": [{"message": "This field is required.", "code": "common:required"}],
"lng": [{"message": "This field is required.", "code": "common:required"}],
"alt": [{"message": "This field is required.", "code": "common:required"}],
"timestamp": [{"message": "This field is required.", "code": "common:required"}]
}
]
```
## Batching
Send up to 200 locations per request for batch uploads or after connectivity issues.
---
# Account Details
:::danger[Retiring August 12, 2026]
Open API 1.0 will be retired on **August 12, 2026**. After this date, all 1.0 endpoints and webhooks will no longer be available. Open API 2.0 is a completely new integration approach. See the [Open API 2.0 documentation](/v2/overview/) to get started.
:::
Use this endpoint to fetch details about accounts that create service requests.
Note: URLs must include the trailing slash.
## Response
### Success (200 OK)
```json
{
"company_name": "Cool Company",
"service_levels": [
"ALS",
"Ambulatory Van",
"BLS",
"CCT",
"FW",
"Homevisit",
"RW",
"SCT",
"Secure Car",
"Sedan",
"SV",
"WC"
],
"facilities": [
{
"name": "Helpful Hospital #1",
"address": "123 Corte Madera Avenue, CA, 94925, United States"
},
{
"name": "Helpful Hospital #0",
"address": "456 Main Street, CA, 94925, United States"
}
]
}
```
## Response Fields
| Field | Nullable | Description |
|---|---|---|
| `company_name` | No | Account company name |
| `service_levels` | No | List of service level types configured by the account |
| `facilities` | No | List of facilities (may be empty array) |
### Facility Object
| Field | Description |
|---|---|
| `name` | Facility name |
| `address` | Facility address |
## When to Use
The [Request Detail](/v1/requests-read/request-detail/) endpoint includes an `account` object. Use this endpoint to:
- Fetch updated account information by ID
- Build a directory of accounts you've received requests from
- Map account service levels to your internal values
- Discover facility locations for an account
## About Accounts
Accounts in VectorCare can:
- Create service requests
- Assign requests to themselves
- Broadcast requests to other accounts
When you receive a request from an account you haven't seen before, use this endpoint to fetch their configuration and create appropriate mappings.
---
# Webhooks
:::danger[Retiring August 12, 2026]
Open API 1.0 will be retired on **August 12, 2026**. After this date, all 1.0 endpoints and webhooks will no longer be available. Open API 2.0 is a completely new integration approach. See the [Open API 2.0 documentation](/v2/overview/) to get started.
:::
Webhooks notify your system when events occur in VectorCare.
## Setup
1. Log into VectorCare as an account admin
2. Navigate to **Settings** → **Open API**
3. Set your webhook URL (must be HTTPS)
## Webhook Format
```json
{
"event_id": "EVENT_ID",
"event_type": "request.status.available",
"event": {
"request_id": "ABCD1234",
"request_current_state": "accepted"
}
}
```
| Field | Description |
|---|---|
| `event_id` | Unique ID for deduplication |
| `event_type` | Type of event (see below) |
| `event` | Event payload |
## Event Types
| Event Type | Description |
|---|---|
| `request.state.available` | Request is available to your account |
| `request.state.unavailable` | Request is no longer available |
| `request.data.updated` | Request data was modified |
| `request.state.pending` | Request was broadcast (limited data) |
## Headers
| Header | Description |
|---|---|
| `VectorCare-Environment` | `development` or `production` |
| `VectorCare-Namespace` | `vectorcare` or `kaiser` |
| `X-VectorCare-Signature` | Signature for verification |
## Standing Order Webhooks
For standing orders, you may receive bulk webhooks:
```json
{
"event_id": "EVENT_ID",
"event_type": "collection.state.updated",
"event": {
"collection_id": "STANDING_ORDER_ID",
"collection_current_state": "accepted",
"request_ids": ["ABCD1234", "EFGH5678", "IJKL9012"]
}
}
```
## Verification
Verify webhooks using RSA-SHA256 with the public key from your VectorCare Open API settings. Base64 decode the `X-VectorCare-Signature` header and verify it against the raw request body.
## Best Practices
- **Respond within 10 seconds** with a 2xx status
- **Use async processing** for heavy work
- **Deduplicate using event_id**
- **Set unique constraint on request_id**
- **Avoid rate limiting** webhook requests
## Retry Behavior
| Attempt | Delay |
|---|---|
| 1st | Immediate |
| 2nd | 8 seconds |
| 3rd | 64 seconds |
## Pending State Webhooks
For `request.state.pending` webhooks, these fields are omitted to protect PHI:
- `transport_pickup_time`
- `transport_agreed_for_time`
- `enabled_patient_fields`
- `enabled_request_fields`
- `patient_dob`
Pending requests may expire without becoming available.
---