# Logistics · Driver

Part of AppEngine API Documentation. Full index: https://appengine.appmint.io/documentation.md
## GET /client/logistics/init

**Get client init data**

`operationId: DeliveryClientController_getInitData`

Everything a logistics client needs on start-up in one call — the caller's agent profile if they have one, delivery configuration and current state. Saves a cold client several round trips.

#### Signature

```http
GET /client/logistics/init () -> Init payload
```

#### Access

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

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |

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

#### See also

- `GET /client/logistics/me`

### 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` | Init payload |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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 /client/logistics/register

**Register as a delivery driver**

`operationId: DeliveryClientController_registerAsAgent`

Registers the calling customer as a delivery agent with their vehicle details. Registration does **not** grant the ability to take jobs — an operator still has to approve the agent, so expect a pending state after this succeeds.

#### Signature

```http
POST /client/logistics/register (body) -> The agent profile
```

#### Access

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

#### Notes

- Approval is a separate operator action.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |

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

#### See also

- `GET /client/logistics/me`

### 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

Vehicle details.

```json
{
  "vehicleType": "car",
  "vehicleMake": "Toyota",
  "vehicleModel": "Corolla",
  "vehicleYear": 2021,
  "licensePlate": "7ABC123",
  "licensePlateState": "CA"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The agent profile |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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 /client/logistics/me

**Get my agent profile**

`operationId: DeliveryClientController_getMyProfile`

The caller's own driver profile — approval status, vehicle, performance and earnings.

#### Signature

```http
GET /client/logistics/me () -> The agent profile
```

#### Access

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

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | NO_AGENT_PROFILE | Agent profile not found. Please register first. | The caller is not a registered delivery agent. | Register with `POST /client/logistics/register`. |

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

#### See also

- `PUT /client/logistics/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. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The agent profile |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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 profile not found. Please register first. — The caller is not a registered delivery agent. |
| `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 /client/logistics/availability

**Set my availability**

`operationId: DeliveryClientController_updateAvailability`

Goes online or offline. Offline drivers receive no job offers — this is the switch a driver flips at the start and end of a shift.

#### Signature

```http
PUT /client/logistics/availability (body) -> The result
```

#### Access

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

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | NO_AGENT_PROFILE | Agent profile not found. Please register first. | The caller is not a registered delivery agent. | Register with `POST /client/logistics/register`. |

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

#### See also

- `GET /client/logistics/jobs/available`

### 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 availability.

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

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The result |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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 profile not found. Please register first. — The caller is not a registered delivery agent. |
| `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 /client/logistics/location

**Update my location**

`operationId: DeliveryClientController_updateLocation`

Reports the driver's position. Called continuously by the driver app while online; it drives proximity dispatch and, on an active job, the customer's tracking map.

#### Signature

```http
PUT /client/logistics/location (body) -> The result
```

#### Access

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

#### Notes

- Visible to customers on an active job.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | NO_AGENT_PROFILE | Agent profile not found. Please register first. | The caller is not a registered delivery agent. | Register with `POST /client/logistics/register`. |

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

#### See also

- `PUT /client/logistics/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. |

### Request body

The location.

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

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The result |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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 profile not found. Please register first. — The caller is not a registered delivery agent. |
| `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 /client/logistics/jobs

**List my jobs**

`operationId: DeliveryClientController_getMyJobs`

The caller's jobs. `role` selects the perspective — as the driver, or as the customer who ordered them — since one account can be both.

#### Signature

```http
GET /client/logistics/jobs (status?: string, role?: string, page?: integer, pageSize?: integer) -> Jobs
```

#### Access

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

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |

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

#### See also

- `GET /client/logistics/jobs/available`

### 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 | — |  |
| `role` | query | string | — | `agent` or `customer`. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Jobs |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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 /client/logistics/jobs/available

**List jobs I can take**

`operationId: DeliveryClientController_getAvailableJobs`

Jobs offered or broadcast that this driver is eligible for, given their zone, vehicle and approval status. Empty while offline.

#### Signature

```http
GET /client/logistics/jobs/available () -> Available jobs
```

#### Access

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

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | NO_AGENT_PROFILE | Agent profile not found. Please register first. | The caller is not a registered delivery agent. | Register with `POST /client/logistics/register`. |

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

#### See also

- `PUT /client/logistics/jobs/{jobId}/accept`

### 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` | Available jobs |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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 profile not found. Please register first. — The caller is not a registered delivery agent. |
| `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 /client/logistics/jobs/{jobId}

**Get one of my jobs**

`operationId: DeliveryClientController_getJob`

A job the caller is party to — as driver or as customer. Someone else's job is not readable here.

#### Signature

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

#### Access

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

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id, or it is not the caller's. | List your jobs with `GET /client/logistics/jobs`. |

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

#### See also

- `GET /client/logistics/jobs/{jobId}/contacts`

### 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` | Not authenticated — No customer or user could be resolved from the token. |
| `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, or it is not the caller's. |
| `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 /client/logistics/jobs/{jobId}/accept

**Accept a job**

`operationId: DeliveryClientController_acceptJob`

Takes an available job. Broadcast jobs are first-come — a job someone else already took returns 409, which is expected rather than an error to retry.

#### Signature

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

#### Access

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

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id, or it is not the caller's. | List your jobs with `GET /client/logistics/jobs`. |
| `409` | JOB_UNAVAILABLE | Job is no longer available | Another driver accepted it first. | Pick another job from the available list. |

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

#### See also

- `GET /client/logistics/jobs/available`

### 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` | Not authenticated — No customer or user could be resolved from the token. |
| `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, or it is not the caller's. |
| `409` | Job is no longer available — Another driver accepted it first. |
| `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 /client/logistics/jobs/{jobId}/reject

**Reject a job**

`operationId: DeliveryClientController_rejectJob`

Declines an offered job, returning it to the pool for other drivers.

#### Signature

```http
PUT /client/logistics/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 |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id, or it is not the caller's. | List your jobs with `GET /client/logistics/jobs`. |

Plus the standard platform errors: `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 reason.

```json
{
  "reason": "Too far from me"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The updated job |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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, or it is not the caller's. |
| `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 /client/logistics/jobs/{jobId}/start-pickup

**Start the pickup leg**

`operationId: DeliveryClientController_startPickup`

Marks the driver en route to collect. This is what starts the customer's tracking view for the job.

#### Signature

```http
PUT /client/logistics/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 |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id, or it is not the caller's. | List your jobs with `GET /client/logistics/jobs`. |

Plus the standard platform errors: `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` | Not authenticated — No customer or user could be resolved from the token. |
| `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, or it is not the caller's. |
| `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 /client/logistics/jobs/{jobId}/arrive-pickup

**Arrive at pickup**

`operationId: DeliveryClientController_arrivePickup`

Marks arrival at the pickup, stamping the time any waiting charge is measured from.

#### Signature

```http
PUT /client/logistics/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 |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id, or it is not the caller's. | List your jobs with `GET /client/logistics/jobs`. |

Plus the standard platform errors: `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.7936,
  "lng": -122.3958
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The updated job |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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, or it is not the caller's. |
| `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 /client/logistics/jobs/{jobId}/complete-pickup

**Complete the pickup**

`operationId: DeliveryClientController_completePickup`

Records that the goods were collected — custody passes to the driver here. Upload pickup photos first; they are the driver's record of what condition the items were in.

#### Signature

```http
PUT /client/logistics/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 |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id, or it is not the caller's. | List your jobs with `GET /client/logistics/jobs`. |

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

#### See also

- `POST /client/logistics/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.

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

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The updated job |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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, or it is not the caller's. |
| `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 /client/logistics/jobs/{jobId}/start-dropoff

**Start the dropoff leg**

`operationId: DeliveryClientController_startDropoff`

Marks the driver en route to the delivery address.

#### Signature

```http
PUT /client/logistics/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 |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id, or it is not the caller's. | List your jobs with `GET /client/logistics/jobs`. |

Plus the standard platform errors: `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` | Not authenticated — No customer or user could be resolved from the token. |
| `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, or it is not the caller's. |
| `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 /client/logistics/jobs/{jobId}/arrive-dropoff

**Arrive at dropoff**

`operationId: DeliveryClientController_arriveDropoff`

Marks arrival at the delivery address.

#### Signature

```http
PUT /client/logistics/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 |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id, or it is not the caller's. | List your jobs with `GET /client/logistics/jobs`. |

Plus the standard platform errors: `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` | Not authenticated — No customer or user could be resolved from the token. |
| `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, or it is not the caller's. |
| `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 /client/logistics/jobs/{jobId}/complete-dropoff

**Complete the dropoff**

`operationId: DeliveryClientController_completeDropoff`

Records the handover — who received it, signature, notes. Attach a `proof` image: a delivery disputed later with no proof is generally resolved against the driver.

#### Signature

```http
PUT /client/logistics/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 |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id, or it is not the caller's. | List your jobs with `GET /client/logistics/jobs`. |

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

#### See also

- `POST /client/logistics/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` | Not authenticated — No customer or user could be resolved from the token. |
| `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, or it is not the caller's. |
| `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 /client/logistics/jobs/{jobId}/complete

**Complete a job**

`operationId: DeliveryClientController_completeJob`

Closes the delivery. Driver pay is settled by the operator's payment run, not by this call.

#### Signature

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

#### Access

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

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id, or it is not the caller's. | List your jobs with `GET /client/logistics/jobs`. |

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

#### See also

- `POST /client/logistics/payouts/request`

### 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` | Not authenticated — No customer or user could be resolved from the token. |
| `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, or it is not the caller's. |
| `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 /client/logistics/jobs/{jobId}/tracking

**Update job tracking**

`operationId: DeliveryClientController_updateJobTracking`

Pushes the driver's live position onto the job. This is the feed behind the customer's tracking map, so it is customer-visible.

#### Signature

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

#### Access

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

#### Notes

- Customer-visible.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id, or it is not the caller's. | List your jobs with `GET /client/logistics/jobs`. |

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

#### See also

- `GET /client/logistics/orders/{jobId}/track`

### 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": 37.79,
  "lng": -122.4,
  "heading": 92
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The updated job |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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, or it is not the caller's. |
| `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 /client/logistics/jobs/{jobId}/issues

**Get job issues**

`operationId: DeliveryClientController_getJobIssues`

Issues raised on a job the caller is party to.

#### Signature

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

#### Access

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

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id, or it is not the caller's. | List your jobs with `GET /client/logistics/jobs`. |

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

#### See also

- `POST /client/logistics/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` | Not authenticated — No customer or user could be resolved from the token. |
| `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, or it is not the caller's. |
| `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 /client/logistics/jobs/{jobId}/issues

**Report a job issue**

`operationId: DeliveryClientController_reportIssue`

Raises a problem from the caller's side — access refused, damage, a wrong address. Photos attached here are what support the driver's account if the delivery is later disputed.

#### Signature

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

#### Access

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

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id, or it is not the caller's. | List your jobs with `GET /client/logistics/jobs`. |

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

#### See also

- `GET /client/logistics/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. |

### Request body

The issue.

```json
{
  "reportedBy": "driver",
  "type": "access_denied",
  "description": "Gate code did not work"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The issue |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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, or it is not the caller's. |
| `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 /client/logistics/jobs/{jobId}/images

**Get job images**

`operationId: DeliveryClientController_getJobImages`

Images attached to a job, optionally by category.

#### Signature

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

#### Access

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

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id, or it is not the caller's. | List your jobs with `GET /client/logistics/jobs`. |

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

#### See also

- `POST /client/logistics/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 | — |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Images |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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, or it is not the caller's. |
| `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 /client/logistics/jobs/{jobId}/images

**Add job images**

`operationId: DeliveryClientController_addJobImages`

Attaches uploaded images to a job under a category — `proof` for delivery evidence, `pickup`/`dropoff` for condition, `damage` for a claim. Upload the file through `POST /client/logistics/upload` first; this takes paths, not file data.

#### Signature

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

#### Access

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

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id, or it is not the caller's. | List your jobs with `GET /client/logistics/jobs`. |

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

#### See also

- `POST /client/logistics/upload`

### 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": "logistics/jobs/JOB-4821/proof_img.jpg",
      "url": "https://cdn.example.com/logistics/jobs/JOB-4821/proof_img.jpg"
    }
  ],
  "category": "proof"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The result |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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, or it is not the caller's. |
| `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 /client/logistics/jobs/{jobId}/messages

**Get job messages**

`operationId: DeliveryClientController_getMessages`

The job's message thread.

#### Signature

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

#### Access

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

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id, or it is not the caller's. | List your jobs with `GET /client/logistics/jobs`. |

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

#### See also

- `PUT /client/logistics/jobs/{jobId}/messages/read`

### 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` | Not authenticated — No customer or user could be resolved from the token. |
| `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, or it is not the caller's. |
| `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 /client/logistics/jobs/{jobId}/messages

**Send a job message**

`operationId: DeliveryClientController_sendMessage`

Posts a message on the job thread. It reaches the other party — driver to customer or the reverse — so it is outward-facing.

#### Signature

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

#### Access

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

#### Notes

- Reaches the other party.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id, or it is not the caller's. | List your jobs with `GET /client/logistics/jobs`. |

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

#### See also

- `GET /client/logistics/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
{
  "content": "I'm at the gate, which buzzer?"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The message |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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, or it is not the caller's. |
| `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 /client/logistics/jobs/{jobId}/messages/read

**Mark job messages read**

`operationId: DeliveryClientController_markMessagesRead`

Clears the unread state on a job thread for the caller.

#### Signature

```http
PUT /client/logistics/jobs/{jobId}/messages/read (jobId: string) -> The result
```

#### Access

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

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id, or it is not the caller's. | List your jobs with `GET /client/logistics/jobs`. |

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

#### See also

- `GET /client/logistics/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` | The result |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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, or it is not the caller's. |
| `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 /client/logistics/jobs/{jobId}/contacts

**Get job contacts**

`operationId: DeliveryClientController_getJobContacts`

The contact details for the job — pickup and dropoff contacts, and the other party. Contains personal phone numbers, so it is scoped to jobs the caller is actually on.

#### Signature

```http
GET /client/logistics/jobs/{jobId}/contacts (jobId: string) -> Contacts
```

#### Access

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

#### Notes

- Returns personal contact details.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id, or it is not the caller's. | List your jobs with `GET /client/logistics/jobs`. |

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

#### See also

- `POST /client/logistics/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` | Contacts |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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, or it is not the caller's. |
| `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 /client/logistics/upload

**Upload a file**

`operationId: DeliveryClientController_uploadFile`

Uploads a file as `multipart/form-data` under the field name `file`, and returns its stored path for attaching to a job.

The storage path is built from two **form fields sent alongside the file**, not from query parameters: `jobId` and `status`. With a `jobId` the file lands at `logistics/jobs/{jobId}/{status}_{filename}`; without one it goes to `logistics/uploads/{status}_{filename}`, where nothing links it to a delivery. `status` defaults to `general`.

#### Signature

```http
POST /client/logistics/upload (body) -> The stored file
```

#### Access

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

#### Notes

- Send `jobId` as a form field or the file is orphaned from the delivery.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `400` | NO_FILE | No file provided | No `file` part was sent. | Send multipart form data with a `file` field. |
| `500` | UPLOAD_FAILED | Failed to upload file | Storage rejected the file. | Retry. |

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

#### See also

- `POST /client/logistics/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. |

### Request body

Multipart form: `file`, plus optional `jobId` and `status` fields.

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The stored file |
| `400` | No file provided — No `file` part was sent. |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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` | Failed to upload file — Storage rejected the file. |

## GET /client/logistics/payout-methods

**List my payout methods**

`operationId: DeliveryClientController_getPayoutMethods`

How the driver gets paid — bank, PayPal, Venmo, Cash App, debit card or crypto. Account numbers are stored masked; full values are not returned.

#### Signature

```http
GET /client/logistics/payout-methods () -> Payout methods
```

#### Access

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

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | NO_AGENT_PROFILE | Agent profile not found. Please register first. | The caller is not a registered delivery agent. | Register with `POST /client/logistics/register`. |

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

#### See also

- `POST /client/logistics/payout-methods`

### 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` | Payout methods |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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 profile not found. Please register first. — The caller is not a registered delivery agent. |
| `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 /client/logistics/payout-methods

**Add a payout method**

`operationId: DeliveryClientController_addPayoutMethod`

Adds a way for the driver to be paid. `type` selects which sub-object matters — send `bank` for a bank account, `paypal` for a PayPal email, and so on; the others are ignored.

**The body carries bank account and card details.** Never log it, and send it only over TLS. A new method typically starts unverified and is not usable for a payout until it is verified.

`isDefault` makes it the target for payout requests that name no method.

#### Signature

```http
POST /client/logistics/payout-methods (body) -> The payout method
```

#### Access

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

#### Notes

- Sensitive payload — do not log the request body.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | NO_AGENT_PROFILE | Agent profile not found. Please register first. | The caller is not a registered delivery agent. | Register with `POST /client/logistics/register`. |

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

#### See also

- `PUT /client/logistics/payout-methods/{methodId}/default`

### 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 payout method.

```json
{
  "type": "bank",
  "label": "Main checking",
  "isDefault": true,
  "bank": {
    "bankName": "Example Bank",
    "accountType": "checking",
    "routingNumber": "021000021",
    "accountNumber": "000123456789",
    "accountHolderName": "Ada Lovelace",
    "accountHolderType": "individual"
  }
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The payout method |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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 profile not found. Please register first. — The caller is not a registered delivery agent. |
| `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 /client/logistics/payout-methods/{methodId}

**Update a payout method**

`operationId: DeliveryClientController_updatePayoutMethod`

Changes a method's label, default flag or status. Account details themselves are not editable — replace the method instead.

#### Signature

```http
PUT /client/logistics/payout-methods/{methodId} (methodId: string, body) -> The updated method
```

#### Access

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

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |

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

#### See also

- `DELETE /client/logistics/payout-methods/{methodId}`

### 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. |
| `methodId` | path | string | yes | Payout method id. |

### Request body

Fields to change.

```json
{
  "label": "Main checking"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The updated method |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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. |

## DELETE /client/logistics/payout-methods/{methodId}

**Remove a payout method**

`operationId: DeliveryClientController_removePayoutMethod`

Deletes a payout method. Removing the default leaves the driver with no default — a payout request that names no method then has nowhere to go, so set another default first.

#### Signature

```http
DELETE /client/logistics/payout-methods/{methodId} (methodId: string) -> The result
```

#### Access

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

#### Notes

- Set another default before removing the current one.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |

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

#### See also

- `PUT /client/logistics/payout-methods/{methodId}/default`

### 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. |
| `methodId` | path | string | yes | Payout method id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The result |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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
}
```

## PUT /client/logistics/payout-methods/{methodId}/default

**Set the default payout method**

`operationId: DeliveryClientController_setDefaultPayoutMethod`

Makes one method the default. Payout requests without an explicit `methodId` are paid to it.

#### Signature

```http
PUT /client/logistics/payout-methods/{methodId}/default (methodId: string) -> The result
```

#### Access

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

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |

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

#### See also

- `POST /client/logistics/payouts/request`

### 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. |
| `methodId` | path | string | yes | Payout method id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The result |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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 /client/logistics/payouts

**List my payouts**

`operationId: DeliveryClientController_getMyPayouts`

The driver's payout history and their states.

#### Signature

```http
GET /client/logistics/payouts (status?: string, page?: integer, pageSize?: integer) -> Payouts
```

#### Access

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

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | NO_AGENT_PROFILE | Agent profile not found. Please register first. | The caller is not a registered delivery agent. | Register with `POST /client/logistics/register`. |

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

#### See also

- `POST /client/logistics/payouts/request`

### 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` | Payouts |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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 profile not found. Please register first. — The caller is not a registered delivery agent. |
| `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 /client/logistics/payouts/request

**Request a payout**

`operationId: DeliveryClientController_requestPayout`

Asks for accumulated earnings to be paid out, to `methodId` or to the default method. The request enters a pending state for the operator to process — this does not itself move money.

#### Signature

```http
POST /client/logistics/payouts/request (body) -> The payout request
```

#### Access

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

#### Notes

- Creates a request; the operator settles it.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | NO_AGENT_PROFILE | Agent profile not found. Please register first. | The caller is not a registered delivery agent. | Register with `POST /client/logistics/register`. |
| `400` | INVALID_AMOUNT | Invalid amount | The amount is missing, non-positive or above the available balance. | Check available earnings first. |

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

#### See also

- `GET /client/logistics/payouts`

### 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 request.

```json
{
  "amount": 12500
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The payout request |
| `400` | Invalid amount — The amount is missing, non-positive or above the available balance. |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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 profile not found. Please register first. — The caller is not a registered delivery agent. |
| `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 /client/logistics/payments/{jobId}

**Get a job's payment**

`operationId: DeliveryClientController_getJobPayment`

What was charged and paid on one job. `includeTransaction=true` adds the full underlying transaction record, which is more detail than a normal client view needs.

#### Signature

```http
GET /client/logistics/payments/{jobId} (jobId: string, includeTransaction?: boolean) -> The payment
```

#### Access

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

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |
| `404` | JOB_NOT_FOUND | Delivery job not found | No job has that id, or it is not the caller's. | List your jobs with `GET /client/logistics/jobs`. |

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

#### See also

- `GET /client/logistics/payments`

### 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. |
| `includeTransaction` | query | boolean | — | Include the full transaction record. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The payment |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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, or it is not the caller's. |
| `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 /client/logistics/payments

**List my payments**

`operationId: DeliveryClientController_getPaymentHistory`

Payments across the caller's jobs.

#### Signature

```http
GET /client/logistics/payments (status?: string, page?: integer, pageSize?: integer) -> Payments
```

#### Access

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

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_AUTHENTICATED | Not authenticated | No customer or user could be resolved from the token. | Sign in. |

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

#### See also

- `GET /client/logistics/payments/{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. |
| `page` | query | integer | — |  |
| `pageSize` | query | integer | — |  |
| `status` | query | string | — |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Payments |
| `401` | Not authenticated — No customer or user could be resolved from the token. |
| `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. |

