# Logistics

Part of AppEngine API Documentation. Full index: https://appengine.appmint.io/documentation.md
## POST /logistics/delivery/geocode

**Geocode an address**

`operationId: DeliveryController_geocodeAddress`

Turns a free-text address into coordinates.

**Never returns an error status.** A failure comes back as HTTP 200 with `{ "success": false, "error": "Could not geocode address" }` — branch on `success`, not on the status code.

#### Signature

```http
POST /logistics/delivery/geocode (body) -> Coordinates, or `success: false` on failure
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Failure is signalled in the body, not the status.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /logistics/delivery/validate-address`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The address.

```json
{
  "address": "1 Market St, San Francisco, CA"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Coordinates, or `success: false` on failure |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

Example response:

```json
{
  "success": true,
  "lat": 37.7936,
  "lng": -122.3958
}
```

## POST /logistics/delivery/validate-address

**Validate an address**

`operationId: DeliveryController_validateAddress`

Checks whether an address is deliverable, accepting either a string or a structured address. Worth running before creating a job — a job with an unresolvable dropoff wastes a driver's trip.

#### Signature

```http
POST /logistics/delivery/validate-address (body) -> The validation result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /logistics/delivery/quote`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The address.

```json
{
  "address": {
    "street": "1 Market St",
    "city": "San Francisco",
    "state": "CA",
    "zipCode": "94105"
  }
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The validation result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /logistics/delivery/quote

**Get a delivery price quote**

`operationId: DeliveryController_getValidatedPriceQuote`

Prices a delivery from its stops, geocoding each one and applying the zone and distance rules. A quote, not a commitment — the price on a created job is recalculated from the job's own stops.

#### Signature

```http
POST /logistics/delivery/quote (body) -> The quote
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | NO_CONFIG | No delivery config found | The org has no delivery configuration. | Configure delivery first. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /logistics/delivery/jobs`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The stops to price.

```json
{
  "stops": [
    {
      "type": "pickup",
      "location": {
        "address": "1 Market St, San Francisco, CA"
      }
    },
    {
      "type": "dropoff",
      "location": {
        "address": "500 Howard St, San Francisco, CA"
      }
    }
  ]
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The quote |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | No delivery config found — The org has no delivery configuration. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /logistics/delivery/route-distance

**Calculate route distance**

`operationId: DeliveryController_getRouteDistance`

Road distance across a sequence of addresses, in order. Driving distance rather than straight-line — the figure that drives pricing.

#### Signature

```http
POST /logistics/delivery/route-distance (body) -> The route distance
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /logistics/delivery/quote`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The stops, in order.

```json
{
  "stops": [
    {
      "address": "1 Market St, San Francisco, CA"
    },
    {
      "address": "500 Howard St, San Francisco, CA"
    }
  ]
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The route distance |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /logistics/delivery/config

**Get the delivery configuration**

`operationId: DeliveryController_getConfig`

The org's delivery rules — pricing bands, distance rates, agent requirements. Pass `name` for a specific named config.

#### Signature

```http
GET /logistics/delivery/config (name?: string) -> The configuration
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | NO_CONFIG | No delivery config found | No configuration exists under that name. | Check the name, or configure delivery. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /logistics/delivery/zones`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `name` | query | string | — |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The configuration |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | No delivery config found — No configuration exists under that name. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /logistics/delivery/zones

**List delivery zones**

`operationId: DeliveryController_listZones`

The geographic zones deliveries are priced and dispatched within.

#### Signature

```http
GET /logistics/delivery/zones (status?: string, page?: integer, pageSize?: integer) -> Zones
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /logistics/delivery/zones/lookup`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `status` | query | string | — |  |
| `page` | query | integer | — |  |
| `pageSize` | query | integer | — |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Zones |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /logistics/delivery/zones/lookup

**Find the zone for a location**

`operationId: DeliveryController_findZoneForLocation`

Resolves coordinates to the zone containing them — how a job gets its zone, and therefore its price band. A point outside every zone has no zone, which usually means the delivery cannot be served.

#### Signature

```http
GET /logistics/delivery/zones/lookup (lat?: number, lng?: number) -> The containing zone, if any
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /logistics/delivery/zones/{zoneName}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `lat` | query | number | yes |  |
| `lng` | query | number | yes |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The containing zone, if any |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /logistics/delivery/zones/{zoneName}

**Get a delivery zone**

`operationId: DeliveryController_getZone`

One zone with its boundary and pricing.

#### Signature

```http
GET /logistics/delivery/zones/{zoneName} (zoneName: string) -> The zone
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /logistics/delivery/zones`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `zoneName` | path | string | yes | Zone name. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The zone |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /logistics/delivery/agents

**List delivery agents**

`operationId: DeliveryController_listAgents`

Agents with their status, availability and type.

#### Signature

```http
GET /logistics/delivery/agents (status?: string, availability?: string, type?: string, page?: integer, pageSize?: integer) -> Agents
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /logistics/delivery/agents/online`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `status` | query | string | — | Approval status. |
| `availability` | query | string | — |  |
| `type` | query | string | — |  |
| `page` | query | integer | — |  |
| `pageSize` | query | integer | — |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Agents |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /logistics/delivery/agents/online

**List online agents**

`operationId: DeliveryController_getOnlineAgents`

Agents currently available, optionally near a point — the dispatcher's view of who can actually take a job right now.

#### Signature

```http
GET /logistics/delivery/agents/online (lat?: number, lng?: number, radius?: number) -> Online agents
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /logistics/delivery/jobs/{jobId}/alert-agents`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `lat` | query | number | — |  |
| `lng` | query | number | — |  |
| `radius` | query | number | — | Miles from the point. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Online agents |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /logistics/delivery/agents/{agentId}

**Get a delivery agent**

`operationId: DeliveryController_getAgent`

One agent with their profile, status and performance.

#### Signature

```http
GET /logistics/delivery/agents/{agentId} (agentId: string) -> The agent
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | AGENT_NOT_FOUND | Agent not found | No agent has that id. | List agents with `GET /logistics/delivery/agents`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /logistics/delivery/agents/{agentId}/approve`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `agentId` | path | string | yes | Delivery agent id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The agent |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Agent not found — No agent has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/agents/{agentId}/location

**Update an agent's location**

`operationId: DeliveryController_updateAgentLocation`

Records where an agent is. Called continuously by the driver app — this feeds proximity dispatch and live tracking, so a stale location means jobs are offered to the wrong drivers.

#### Signature

```http
PUT /logistics/delivery/agents/{agentId}/location (agentId: string, body) -> The result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | AGENT_NOT_FOUND | Agent not found | No agent has that id. | List agents with `GET /logistics/delivery/agents`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /logistics/delivery/agents/{agentId}/availability`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `agentId` | path | string | yes | Delivery agent id. |

### Request body

The location.

```json
{
  "lat": 40.7128,
  "lng": -74.006
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Agent not found — No agent has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/agents/{agentId}/availability

**Update an agent's availability**

`operationId: DeliveryController_updateAgentAvailability`

Sets an agent online or offline. Offline agents receive no job offers.

#### Signature

```http
PUT /logistics/delivery/agents/{agentId}/availability (agentId: string, body) -> The result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | AGENT_NOT_FOUND | Agent not found | No agent has that id. | List agents with `GET /logistics/delivery/agents`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /logistics/delivery/agents/online`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `agentId` | path | string | yes | Delivery agent id. |

### Request body

The availability.

```json
{
  "availability": "online"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Agent not found — No agent has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/agents/{agentId}/approve

**Approve an agent**

`operationId: DeliveryController_approveAgent`

Approves an agent to take jobs. This is the gate between someone registering and them being able to collect a customer's goods — approve only after the background and document checks are done.

#### Signature

```http
PUT /logistics/delivery/agents/{agentId}/approve (agentId: string, body) -> The result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Grants access to customer deliveries.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | AGENT_NOT_FOUND | Agent not found | No agent has that id. | List agents with `GET /logistics/delivery/agents`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /logistics/delivery/agents/{agentId}/reject`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `agentId` | path | string | yes | Delivery agent id. |

### Request body

Optional approval notes.

```json
{
  "notes": "Licence and insurance verified"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Agent not found — No agent has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/agents/{agentId}/suspend

**Suspend an agent**

`operationId: DeliveryController_suspendAgent`

Stops an approved agent taking new jobs. Jobs already in progress are not reassigned by this call — check for active jobs and reassign them, or the delivery stalls with a suspended driver holding the goods.

#### Signature

```http
PUT /logistics/delivery/agents/{agentId}/suspend (agentId: string, body) -> The result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Does not reassign in-flight jobs.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | AGENT_NOT_FOUND | Agent not found | No agent has that id. | List agents with `GET /logistics/delivery/agents`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /logistics/delivery/jobs/{jobId}/assign`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `agentId` | path | string | yes | Delivery agent id. |

### Request body

Why they are suspended.

```json
{
  "reason": "Under investigation"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Agent not found — No agent has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/agents/{agentId}/reject

**Reject an agent application**

`operationId: DeliveryController_rejectAgent`

Declines an agent's registration. A reason is worth giving — it is what the applicant sees.

#### Signature

```http
PUT /logistics/delivery/agents/{agentId}/reject (agentId: string, body) -> The result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | AGENT_NOT_FOUND | Agent not found | No agent has that id. | List agents with `GET /logistics/delivery/agents`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /logistics/delivery/agents/{agentId}/approve`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `agentId` | path | string | yes | Delivery agent id. |

### Request body

Why they were rejected.

```json
{
  "reason": "Insurance documentation incomplete"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Agent not found — No agent has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /logistics/delivery/agents/{agentId}/available-jobs

**List jobs available to an agent**

`operationId: DeliveryController_getAvailableJobsForAgent`

Jobs this agent could take, filtered by their zone, vehicle type and requirements.

#### Signature

```http
GET /logistics/delivery/agents/{agentId}/available-jobs (agentId: string) -> Available jobs
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | AGENT_NOT_FOUND | Agent not found | No agent has that id. | List agents with `GET /logistics/delivery/agents`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /logistics/delivery/jobs/{jobId}/offer`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `agentId` | path | string | yes | Delivery agent id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Available jobs |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Agent not found — No agent has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/agents/{agentId}/recalculate-performance

**Recalculate an agent's performance**

`operationId: DeliveryController_recalculateAgentPerformance`

Rebuilds an agent's performance metrics from their delivery history. Useful after correcting job data; the recalculated figures can change the agent's standing and job priority.

#### Signature

```http
PUT /logistics/delivery/agents/{agentId}/recalculate-performance (agentId: string) -> The recalculated metrics
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | AGENT_NOT_FOUND | Agent not found | No agent has that id. | List agents with `GET /logistics/delivery/agents`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /logistics/delivery/agents/{agentId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `agentId` | path | string | yes | Delivery agent id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The recalculated metrics |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Agent not found — No agent has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /logistics/delivery/jobs

**List delivery jobs**

`operationId: DeliveryController_listJobs`

Jobs with their status, filterable by agent, customer and zone — the dispatch board.

#### Signature

```http
GET /logistics/delivery/jobs (status?: string, agentId?: string, customerEmail?: string, zone?: string, page?: integer, pageSize?: integer) -> Jobs
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /logistics/delivery/jobs/{jobId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `status` | query | string | — |  |
| `agentId` | query | string | — |  |
| `customerEmail` | query | string | — |  |
| `zone` | query | string | — |  |
| `page` | query | integer | — |  |
| `pageSize` | query | integer | — |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Jobs |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /logistics/delivery/jobs

**Create a delivery job**

`operationId: DeliveryController_createJob`

Creates a job from its stops. A job is created **unassigned** — it still has to be broadcast, offered or assigned before a driver sees it.

`pricing` and `driverPay` may be supplied to override the calculated figures; leave them out to let the zone and distance rules price the job.

With `requireSystemQuote: true` the stops are re-quoted on the server before the job is created — geocoded, checked for serviceability and routed — and the job is refused if any stop fails; the route distance and duration come from that quote, never from the client.

#### Signature

```http
POST /logistics/delivery/jobs (body) -> The job
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Created unassigned — dispatch it separately.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | NO_PICKUP | Job has no pickup location | The stops contain no pickup. | Include a pickup stop. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /logistics/delivery/jobs/{jobId}/broadcast`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The job.

```json
{
  "customer": {
    "firstName": "Ada",
    "lastName": "Lovelace",
    "email": "ada@example.com",
    "phone": "+15551234567"
  },
  "stops": [
    {
      "type": "pickup",
      "location": {
        "address": "1 Market St, San Francisco, CA"
      }
    },
    {
      "type": "dropoff",
      "location": {
        "address": "500 Howard St, San Francisco, CA"
      }
    }
  ],
  "customerNotes": "Ring the bell twice"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The job |
| `400` | Job has no pickup location — The stops contain no pickup. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /logistics/delivery/jobs/{jobId}

**Get a delivery job**

`operationId: DeliveryController_getJob`

One job with its stops, agent, status and pricing.

#### Signature

```http
GET /logistics/delivery/jobs/{jobId} (jobId: string) -> The job
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /logistics/delivery/jobs/{jobId}/tracking`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The job |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/jobs/{jobId}/broadcast

**Broadcast a job**

`operationId: DeliveryController_broadcastJob`

Opens a job to every eligible agent — first to accept takes it. Use this when speed matters more than choosing the driver; `offer` targets one agent instead.

#### Signature

```http
PUT /logistics/delivery/jobs/{jobId}/broadcast (jobId: string) -> The updated job
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The updated job |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/jobs/{jobId}/offer

**Offer a job to an agent**

`operationId: DeliveryController_offerJob`

Offers a job to a specific agent, who can accept or reject it. Unlike a broadcast, the job is held for them rather than raced for.

#### Signature

```http
PUT /logistics/delivery/jobs/{jobId}/offer (jobId: string, body) -> The updated job
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /logistics/delivery/jobs/{jobId}/broadcast`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Request body

Which agent.

```json
{
  "agentId": "AGT-4821"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The updated job |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/jobs/{jobId}/assign

**Assign a job to an agent**

`operationId: DeliveryController_assignJob`

Assigns a job directly, with no offer or acceptance step — the dispatcher's override. The agent gets the job whether or not they would have accepted it.

#### Signature

```http
PUT /logistics/delivery/jobs/{jobId}/assign (jobId: string, body) -> The updated job
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Bypasses agent acceptance.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /logistics/delivery/jobs/{jobId}/offer`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Request body

Which agent.

```json
{
  "agentId": "AGT-4821"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The updated job |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /logistics/delivery/jobs/{jobId}/alert-agents

**Alert agents about a job**

`operationId: DeliveryController_sendJobAlertToAgents`

Pushes a notification about a job to a chosen set of agents — by explicit ids, by zone, by online status, or by radius from a point. **Sends real notifications to drivers**, so a broad filter reaches a lot of people at once.

#### Signature

```http
POST /logistics/delivery/jobs/{jobId}/alert-agents (jobId: string, body) -> The updated job
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Sends push notifications — check the filter width first.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /logistics/delivery/agents/online`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Request body

Who to alert. Combine the filters as needed.

```json
{
  "agentIds": [
    "AGT-4821",
    "AGT-4822"
  ]
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The updated job |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/jobs/{jobId}/accept

**Accept a job on an agent's behalf**

`operationId: DeliveryController_acceptJob`

Records that an agent took the job. Racy by nature — a broadcast job already taken returns 409.

#### Signature

```http
PUT /logistics/delivery/jobs/{jobId}/accept (jobId: string, body) -> The updated job
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |
| `409` | JOB_UNAVAILABLE | Job is no longer available | Another agent already took it. | Offer the agent a different job. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /logistics/delivery/jobs/{jobId}/reject`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Request body

Which agent.

```json
{
  "agentId": "AGT-4821"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The updated job |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `409` | Job is no longer available — Another agent already took it. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/jobs/{jobId}/reject

**Reject a job on an agent's behalf**

`operationId: DeliveryController_rejectJob`

Records that an agent declined an offered job, returning it to the pool.

#### Signature

```http
PUT /logistics/delivery/jobs/{jobId}/reject (jobId: string, body) -> The updated job
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /logistics/delivery/jobs/{jobId}/broadcast`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Request body

Which agent, and why.

```json
{
  "agentId": "AGT-4821",
  "reason": "Too far"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The updated job |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/jobs/{jobId}/start-pickup

**Start the pickup leg**

`operationId: DeliveryController_startPickup`

Marks the driver as en route to the pickup. Starts the customer-visible tracking for that leg.

#### Signature

```http
PUT /logistics/delivery/jobs/{jobId}/start-pickup (jobId: string) -> The updated job
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The updated job |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/jobs/{jobId}/arrive-pickup

**Arrive at pickup**

`operationId: DeliveryController_arrivePickup`

Marks the driver as arrived at the pickup, stamping the arrival time — which is what any waiting-time charge is calculated from.

#### Signature

```http
PUT /logistics/delivery/jobs/{jobId}/arrive-pickup (jobId: string, body) -> The updated job
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /logistics/delivery/jobs/{jobId}/adjustments`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Request body

Optional arrival detail.

```json
{
  "lat": 40.7128,
  "lng": -74.006
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The updated job |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/jobs/{jobId}/complete-pickup

**Complete the pickup**

`operationId: DeliveryController_completePickup`

Records that the goods were collected. Attach pickup photos through the images endpoint — this is the point at which custody passes to the driver.

#### Signature

```http
PUT /logistics/delivery/jobs/{jobId}/complete-pickup (jobId: string, body) -> The updated job
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /logistics/delivery/jobs/{jobId}/images`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Request body

Optional pickup detail — signature, notes.

```json
{
  "notes": "Two sealed boxes"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The updated job |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/jobs/{jobId}/start-dropoff

**Start the dropoff leg**

`operationId: DeliveryController_startDropoff`

Marks the driver as en route to the dropoff.

#### Signature

```http
PUT /logistics/delivery/jobs/{jobId}/start-dropoff (jobId: string) -> The updated job
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The updated job |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/jobs/{jobId}/arrive-dropoff

**Arrive at dropoff**

`operationId: DeliveryController_arriveDropoff`

Marks the driver as arrived at the dropoff.

#### Signature

```http
PUT /logistics/delivery/jobs/{jobId}/arrive-dropoff (jobId: string, body) -> The updated job
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Request body

Optional arrival detail.

```json
{
  "lat": 37.7879,
  "lng": -122.3972
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The updated job |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/jobs/{jobId}/complete-dropoff

**Complete the dropoff**

`operationId: DeliveryController_completeDropoff`

Records the handover — recipient name, signature, notes. Proof-of-delivery photos go through the images endpoint with category `proof`; without them a disputed delivery has nothing to stand on.

#### Signature

```http
PUT /logistics/delivery/jobs/{jobId}/complete-dropoff (jobId: string, body) -> The updated job
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /logistics/delivery/jobs/{jobId}/images`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Request body

Handover detail.

```json
{
  "receivedBy": "Ada Lovelace",
  "notes": "Left with reception"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The updated job |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/jobs/{jobId}/complete

**Complete a job**

`operationId: DeliveryController_completeJob`

Closes the job as delivered. Payment is a separate step — completing does not charge the customer or release driver pay.

#### Signature

```http
PUT /logistics/delivery/jobs/{jobId}/complete (jobId: string) -> The updated job
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /logistics/delivery/jobs/{jobId}/process-payment`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The updated job |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/jobs/{jobId}/cancel

**Cancel a job**

`operationId: DeliveryController_cancelJob`

Cancels a delivery. `cancelledBy` records who called it off, which drives who bears any cancellation fee.

**Refunds happen here.** `refund: true` with either `refundAmount` or `refundPercent` returns money to the customer; omit them and nothing is refunded even though the job is cancelled. A job with no completed payment cannot be refunded.

#### Signature

```http
PUT /logistics/delivery/jobs/{jobId}/cancel (jobId: string, body) -> The cancelled job
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Refunds money when asked to — and only when asked to.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |
| `403` | NOT_AUTHORIZED_CANCEL | Not authorized to cancel this job | The caller may not cancel this job. | Cancel as the customer, assigned agent or an admin. |
| `400` | NO_PAYMENT_TO_REFUND | Job has no completed payment to refund | `refund` was requested but nothing was ever charged. | Cancel without a refund. |

Plus the standard platform errors: `401`, `429`, `500`.

#### See also

- `PUT /logistics/delivery/jobs/{jobId}/fail`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Request body

The cancellation.

```json
{
  "cancelledBy": "admin",
  "reason": "Duplicate booking"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The cancelled job |
| `400` | Job has no completed payment to refund — `refund` was requested but nothing was ever charged. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | Not authorized to cancel this job — The caller may not cancel this job. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/jobs/{jobId}/fail

**Mark a job failed**

`operationId: DeliveryController_failJob`

Records a delivery that could not be completed — nobody home, refused, inaccessible. Distinct from a cancellation, which is a decision not to deliver; a failure means the attempt was made, and the two are settled differently.

#### Signature

```http
PUT /logistics/delivery/jobs/{jobId}/fail (jobId: string, body) -> The updated job
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /logistics/delivery/jobs/{jobId}/cancel`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Request body

Why it failed.

```json
{
  "reason": "Recipient not available after three attempts"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The updated job |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/jobs/{jobId}/pricing

**Update a job's pricing**

`operationId: DeliveryController_updateJobPricing`

Overrides the calculated price for a job. Changes what the customer is charged and, depending on the split, what the driver is paid — prefer an adjustment when the change is an addition rather than a correction, because adjustments are itemised and this is not.

#### Signature

```http
PUT /logistics/delivery/jobs/{jobId}/pricing (jobId: string, body) -> The updated job
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Replaces the price without an itemised trail.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /logistics/delivery/jobs/{jobId}/adjustments`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Request body

The new pricing.

```json
{
  "total": 3200,
  "base": 2500,
  "distance": 700
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The updated job |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /logistics/delivery/jobs/{jobId}/images

**Get job images**

`operationId: DeliveryController_getJobImages`

Photos attached to a job, optionally by category — the proof-of-delivery record.

#### Signature

```http
GET /logistics/delivery/jobs/{jobId}/images (jobId: string, category?: string) -> Images
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /logistics/delivery/jobs/{jobId}/images`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |
| `category` | query | string | — | `proof`, `pickup`, `dropoff`, `issue`, `damage`, `other`. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Images |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /logistics/delivery/jobs/{jobId}/images

**Add job images**

`operationId: DeliveryController_addJobImages`

Attaches already-uploaded images to a job under a category. `proof` is the category that backs a delivery against a dispute; `damage` and `issue` support a claim. `stopIndex` ties an image to a specific stop on a multi-stop job.

Upload the file first — this endpoint takes paths and URLs, not file data.

#### Signature

```http
POST /logistics/delivery/jobs/{jobId}/images (jobId: string, body) -> The result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /logistics/delivery/jobs/{jobId}/complete-dropoff`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Request body

The images.

```json
{
  "images": [
    {
      "path": "jobs/4821/proof-1.jpg",
      "url": "https://cdn.example.com/jobs/4821/proof-1.jpg"
    }
  ],
  "category": "proof",
  "stopIndex": 1
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /logistics/delivery/jobs/{jobId}/adjustments

**Get job adjustments**

`operationId: DeliveryController_getJobAdjustments`

The itemised charges and credits on a job — waiting fees, tolls, damage charges, bonuses.

#### Signature

```http
GET /logistics/delivery/jobs/{jobId}/adjustments (jobId: string) -> Adjustments
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /logistics/delivery/jobs/{jobId}/adjustments`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Adjustments |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /logistics/delivery/jobs/{jobId}/adjustments

**Add a job adjustment**

`operationId: DeliveryController_addJobAdjustment`

Adds an itemised charge or credit. `type` says which direction it goes — `debit` charges, `credit` refunds or rewards.

`driverPortion` decides how much of the adjustment reaches the driver. A damage charge with no `driverPortion` is borne entirely by the platform; a bonus with the full amount goes wholly to the driver. Getting this wrong misallocates money between the platform and the courier.

#### Signature

```http
POST /logistics/delivery/jobs/{jobId}/adjustments (jobId: string, body) -> The adjustment
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- `driverPortion` allocates the money — set it deliberately.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |
| `400` | INVALID_AMOUNT | Invalid amount | The amount is missing or not positive. | Use `type` for direction; keep the amount positive. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /logistics/delivery/jobs/{jobId}/adjustments/{adjustmentId}/remove`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Request body

The adjustment.

```json
{
  "category": "waiting_fee",
  "type": "debit",
  "amount": 500,
  "driverPortion": 500,
  "description": "20 minutes waiting at pickup"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The adjustment |
| `400` | Invalid amount — The amount is missing or not positive. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/jobs/{jobId}/adjustments/{adjustmentId}/remove

**Remove a job adjustment**

`operationId: DeliveryController_removeJobAdjustment`

Removes an adjustment from a job. If payment has already been processed, removing it changes the job total without reversing what was charged — reconcile separately.

#### Signature

```http
PUT /logistics/delivery/jobs/{jobId}/adjustments/{adjustmentId}/remove (jobId: string, adjustmentId: string) -> The result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Does not reverse an already-processed charge.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /logistics/delivery/jobs/{jobId}/payment-status`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |
| `adjustmentId` | path | string | yes | Adjustment id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /logistics/delivery/jobs/{jobId}/payment-status

**Get a job's payment status**

`operationId: DeliveryController_getJobPaymentStatus`

Whether the job has been charged, and for how much. Read this before processing payment to avoid double-charging.

#### Signature

```http
GET /logistics/delivery/jobs/{jobId}/payment-status (jobId: string) -> The payment status
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /logistics/delivery/jobs/{jobId}/process-payment`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The payment status |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /logistics/delivery/jobs/{jobId}/process-payment

**Process a job payment**

`operationId: DeliveryController_processJobPayment`

Charges the customer for a completed job, including its adjustments. The job must be completed first.

`forceZeroPayment` settles a job at zero — for a fully comped delivery. It bypasses the amount check, so use it only when the job genuinely should cost nothing.

#### Signature

```http
POST /logistics/delivery/jobs/{jobId}/process-payment (jobId: string, body) -> The payment result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Charges the customer.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |
| `400` | JOB_NOT_COMPLETED | Job must be completed before processing payment | The job has not been completed. | Complete the delivery first. |
| `403` | NOT_AUTHORIZED_PAYMENT | Not authorized to complete this payment | The caller may not process this job's payment. | An admin or the merchant must process it. |

Plus the standard platform errors: `401`, `429`, `500`.

#### See also

- `GET /logistics/delivery/jobs/{jobId}/payment-status`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Request body

Options.

```json
{}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The payment result |
| `400` | Job must be completed before processing payment — The job has not been completed. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | Not authorized to complete this payment — The caller may not process this job's payment. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/jobs/{jobId}/tracking

**Update job live tracking**

`operationId: DeliveryController_updateJobTracking`

Pushes the driver's current position onto the job, which is what a customer's tracking map shows. Called frequently while a job is in progress; the position is visible to the customer.

#### Signature

```http
PUT /logistics/delivery/jobs/{jobId}/tracking (jobId: string, body) -> The result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Customer-visible.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /logistics/delivery/jobs/{jobId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Request body

The position.

```json
{
  "lat": 40.7128,
  "lng": -74.006,
  "heading": 92
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /logistics/delivery/jobs/{jobId}/issues

**Get job issues**

`operationId: DeliveryController_getJobIssues`

Problems raised on a job and their state.

#### Signature

```http
GET /logistics/delivery/jobs/{jobId}/issues (jobId: string) -> Issues
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /logistics/delivery/jobs/{jobId}/issues`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Issues |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /logistics/delivery/jobs/{jobId}/issues

**Report a job issue**

`operationId: DeliveryController_reportIssue`

Raises a problem on a job — damage, access, a wrong address. `reportedBy` records the perspective, which matters when the driver and the customer describe the same event differently. Photos attached here support any later claim.

#### Signature

```http
POST /logistics/delivery/jobs/{jobId}/issues (jobId: string, body) -> The issue
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /logistics/delivery/jobs/{jobId}/issues/{issueId}/resolve`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Request body

The issue.

```json
{
  "reportedBy": "driver",
  "type": "access_denied",
  "description": "Building requires a code nobody provided"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The issue |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/jobs/{jobId}/issues/{issueId}/resolve

**Resolve a job issue**

`operationId: DeliveryController_resolveIssue`

Closes an issue with a resolution. Record what was actually done — the resolution is the record if the delivery is disputed later.

#### Signature

```http
PUT /logistics/delivery/jobs/{jobId}/issues/{issueId}/resolve (jobId: string, issueId: string, body) -> The result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /logistics/delivery/jobs/{jobId}/issues/{issueId}/escalate`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |
| `issueId` | path | string | yes | Issue id. |

### Request body

The resolution.

```json
{
  "resolution": "Customer supplied the door code; delivery completed"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /logistics/delivery/jobs/{jobId}/issues/{issueId}/escalate

**Escalate a job issue**

`operationId: DeliveryController_escalateIssue`

Raises an issue to support. Use it when the resolution needs someone with authority to compensate or reassign, rather than the driver on the ground.

#### Signature

```http
PUT /logistics/delivery/jobs/{jobId}/issues/{issueId}/escalate (jobId: string, issueId: string) -> The result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /logistics/delivery/jobs/{jobId}/issues/{issueId}/resolve`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |
| `issueId` | path | string | yes | Issue id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /logistics/delivery/jobs/{jobId}/messages

**Get job messages**

`operationId: DeliveryController_getJobMessages`

The message thread for a job.

#### Signature

```http
GET /logistics/delivery/jobs/{jobId}/messages (jobId: string) -> Messages
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /logistics/delivery/jobs/{jobId}/messages`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Messages |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /logistics/delivery/jobs/{jobId}/messages

**Send a job message**

`operationId: DeliveryController_sendMessage`

Posts a message on a job's thread — the channel between driver, customer, recipient and support. `sender` records the role, and the message reaches the other parties, so it is outward-facing.

#### Signature

```http
POST /logistics/delivery/jobs/{jobId}/messages (jobId: string, body) -> The message
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Reaches the customer and driver.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id. | List jobs with `GET /logistics/delivery/jobs`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /logistics/delivery/jobs/{jobId}/messages`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `jobId` | path | string | yes | Delivery job id. |

### Request body

The message.

```json
{
  "sender": "support",
  "content": "The driver is 5 minutes away.",
  "type": "text"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The message |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Delivery job not found — No job has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /logistics/delivery/stats

**Get delivery statistics**

`operationId: DeliveryController_getStats`

Delivery volume, completion rate, average times and agent utilisation.

#### Signature

```http
GET /logistics/delivery/stats () -> Statistics
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /logistics/delivery/jobs`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Statistics |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

