@parkgraph/agent-sdk 0.0.0-stage → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/LICENSE +21 -0
- package/README.md +102 -2
- package/index.d.ts +70 -0
- package/index.js +130 -0
- package/package.json +36 -4
- package/types.d.ts +224 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.4.0 — 2026-10-15
|
|
4
|
+
|
|
5
|
+
- First npm release of the typed client documented at https://parkgraph.com/developers/sdk: `ParkGraphClient` with
|
|
6
|
+
`searchLots`, `createSession`, `getSession`, `endSession` and `health()`, and `ParkGraphError` with `status`.
|
|
7
|
+
- Types are generated from Park Graph's OpenAPI spec 1.4.0, including `GET /health`.
|
|
8
|
+
- `apiKey` is optional: `searchLots` works without a key; the other methods surface the API's 401 as a
|
|
9
|
+
`ParkGraphError`.
|
|
10
|
+
- Works with `pk_test_` sandbox keys; `createSession` takes the sandbox-only `test_card`.
|
|
11
|
+
- No dependencies; uses the platform's `fetch` (Node.js 20+).
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Park Graph
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,103 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @parkgraph/agent-sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The typed TypeScript client for the [Park Graph](https://parkgraph.com) parking API. Search lots, book a session,
|
|
4
|
+
check it and end it from LangChain, CrewAI, AutoGPT, Semantic Kernel or your own agent.
|
|
5
|
+
|
|
6
|
+
- No dependencies. Uses the platform's `fetch` (Node.js 20+, browsers, Deno, Bun, edge runtimes).
|
|
7
|
+
- Types generated from Park Graph's OpenAPI spec (`https://parkgraph.com/openapi.json`).
|
|
8
|
+
- `apiKey` is optional: `searchLots` works without a key.
|
|
9
|
+
|
|
10
|
+
Docs: https://parkgraph.com/developers/sdk
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @parkgraph/agent-sdk@1.4.0
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quick start
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { ParkGraphClient } from "@parkgraph/agent-sdk";
|
|
22
|
+
|
|
23
|
+
const pg = new ParkGraphClient({ apiKey: "pk_live_..." });
|
|
24
|
+
|
|
25
|
+
// Search for parking by coordinates
|
|
26
|
+
const { lots } = await pg.searchLots({
|
|
27
|
+
lat: 39.6403,
|
|
28
|
+
lng: -106.3742,
|
|
29
|
+
radius_km: 5,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Book a session
|
|
33
|
+
const { session } = await pg.createSession({
|
|
34
|
+
lot_id: lots[0].id,
|
|
35
|
+
plate: "CO-7891",
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Check status
|
|
39
|
+
const status = await pg.getSession(session.id);
|
|
40
|
+
|
|
41
|
+
// End session
|
|
42
|
+
const receipt = await pg.endSession({
|
|
43
|
+
session_id: session.id,
|
|
44
|
+
session_code: session.session_code,
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## API
|
|
49
|
+
|
|
50
|
+
| Method | Returns |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| `searchLots(params)`: search lots by lat/lng coordinates (no key needed) | `Promise<SearchResult>` |
|
|
53
|
+
| `createSession(params)`: create a parking session | `Promise<{ session: Session }>` |
|
|
54
|
+
| `getSession(sessionId)`: get a session by UUID | `Promise<{ session: SessionDetail }>` |
|
|
55
|
+
| `endSession(params)`: end a session and get the receipt | `Promise<{ session: SessionReceipt }>` |
|
|
56
|
+
| `health()`: check API health | `Promise<{ status, version }>` |
|
|
57
|
+
|
|
58
|
+
## Errors
|
|
59
|
+
|
|
60
|
+
Every non-2xx answer throws a `ParkGraphError` with the HTTP `status`, the API's error `code` and `message`, the
|
|
61
|
+
`requestId` and the raw `body`. A request that can't reach Park Graph throws one with `status` 0.
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { ParkGraphClient, ParkGraphError } from "@parkgraph/agent-sdk";
|
|
65
|
+
|
|
66
|
+
const pg = new ParkGraphClient({ apiKey: "pk_live_..." });
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const { lots } = await pg.searchLots({ lat: 0, lng: 0 });
|
|
70
|
+
} catch (err) {
|
|
71
|
+
if (err instanceof ParkGraphError) {
|
|
72
|
+
console.error(`API error ${err.status}: ${err.message}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Sandbox
|
|
78
|
+
|
|
79
|
+
Use a `pk_test_` key (create one in your Park Graph dashboard, API keys → Test) against the same base URL. Test keys
|
|
80
|
+
see three sandbox lots and pay with Stripe test cards; no real payments are processed. `createSession` takes a
|
|
81
|
+
sandbox-only `test_card`:
|
|
82
|
+
|
|
83
|
+
| `test_card` | Result |
|
|
84
|
+
| --- | --- |
|
|
85
|
+
| `4242 4242 4242 4242` (default) | Successful payment |
|
|
86
|
+
| `4000 0000 0000 0002` | Card declined (`ParkGraphError`, status 402, code `CARD_DECLINED`) |
|
|
87
|
+
| `4000 0000 0000 3220` | 3D Secure required (`payment_status` `requires_action`) |
|
|
88
|
+
|
|
89
|
+
Sandbox docs: https://parkgraph.com/developers/sandbox
|
|
90
|
+
|
|
91
|
+
## Options
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
new ParkGraphClient({
|
|
95
|
+
apiKey: process.env.PARKGRAPH_API_KEY, // optional
|
|
96
|
+
baseUrl: "https://parkgraph.com/api/v1", // default
|
|
97
|
+
fetch, // optional fetch implementation
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## License
|
|
102
|
+
|
|
103
|
+
MIT
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// @parkgraph/agent-sdk: typed client for the Park Graph parking API.
|
|
2
|
+
// The API's request and response shapes live in ./types.js, generated from
|
|
3
|
+
// Park Graph's OpenAPI spec (https://parkgraph.com/openapi.json).
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
CreateSessionRequest,
|
|
7
|
+
CreateSessionResponse,
|
|
8
|
+
EndSessionRequest,
|
|
9
|
+
EndSessionResponse,
|
|
10
|
+
GetSessionResponse,
|
|
11
|
+
Health,
|
|
12
|
+
SearchParkingParams,
|
|
13
|
+
SearchParkingResponse,
|
|
14
|
+
} from "./types.js";
|
|
15
|
+
|
|
16
|
+
export type * from "./types.js";
|
|
17
|
+
|
|
18
|
+
export declare const VERSION: "1.4.0";
|
|
19
|
+
|
|
20
|
+
/** Parameters of searchLots: GET /lots/search. */
|
|
21
|
+
export type SearchParams = SearchParkingParams;
|
|
22
|
+
/** What searchLots resolves to. */
|
|
23
|
+
export type SearchResult = SearchParkingResponse;
|
|
24
|
+
/** Parameters of createSession: POST /sessions. */
|
|
25
|
+
export type CreateSessionParams = CreateSessionRequest;
|
|
26
|
+
/** Parameters of endSession: POST /sessions/end. */
|
|
27
|
+
export type EndSessionParams = EndSessionRequest;
|
|
28
|
+
|
|
29
|
+
export interface ParkGraphConfig {
|
|
30
|
+
/**
|
|
31
|
+
* A Park Graph API key: `pk_live_…`, or `pk_test_…` for the sandbox.
|
|
32
|
+
* Optional: searchLots works without one; the other methods need it.
|
|
33
|
+
*/
|
|
34
|
+
apiKey?: string;
|
|
35
|
+
/** Default https://parkgraph.com/api/v1 */
|
|
36
|
+
baseUrl?: string;
|
|
37
|
+
/** A fetch implementation, if the runtime has none. */
|
|
38
|
+
fetch?: typeof fetch;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** A non-2xx answer from the API, or a request that could not reach it (status 0). */
|
|
42
|
+
export declare class ParkGraphError extends Error {
|
|
43
|
+
readonly name: "ParkGraphError";
|
|
44
|
+
/** HTTP status (0 when Park Graph could not be reached). */
|
|
45
|
+
readonly status: number;
|
|
46
|
+
/** The raw response body. */
|
|
47
|
+
readonly body: string;
|
|
48
|
+
/** The API's error code, e.g. "UNAUTHORIZED" or "RATE_LIMITED". */
|
|
49
|
+
readonly code: string | null;
|
|
50
|
+
/** The API's request id, for support. */
|
|
51
|
+
readonly requestId: string | null;
|
|
52
|
+
constructor(message: string, status: number, body?: string, code?: string | null, requestId?: string | null);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export declare class ParkGraphClient {
|
|
56
|
+
constructor(config?: ParkGraphConfig);
|
|
57
|
+
/** Search lots by lat/lng coordinates. Works without an API key. */
|
|
58
|
+
searchLots(params: SearchParams): Promise<SearchResult>;
|
|
59
|
+
/** Create a parking session. */
|
|
60
|
+
createSession(params: CreateSessionParams): Promise<CreateSessionResponse>;
|
|
61
|
+
/** Get a session by UUID. */
|
|
62
|
+
getSession(sessionId: string): Promise<GetSessionResponse>;
|
|
63
|
+
/** End a session and get the receipt. */
|
|
64
|
+
endSession(params: EndSessionParams): Promise<EndSessionResponse>;
|
|
65
|
+
/** Check API health. */
|
|
66
|
+
health(): Promise<Health>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { ParkGraphClient as ParkGraph };
|
|
70
|
+
export default ParkGraphClient;
|
package/index.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// @parkgraph/agent-sdk: typed client for the Park Graph parking API.
|
|
2
|
+
// Docs: https://parkgraph.com/developers/sdk
|
|
3
|
+
//
|
|
4
|
+
// Plain ESM with no dependencies; uses the platform's fetch (Node 20+,
|
|
5
|
+
// browsers, Deno, Bun, edge runtimes). Types: index.d.ts, with the API's
|
|
6
|
+
// shapes in types.d.ts, generated from Park Graph's OpenAPI spec.
|
|
7
|
+
|
|
8
|
+
export const VERSION = "1.4.0";
|
|
9
|
+
|
|
10
|
+
const DEFAULT_BASE_URL = "https://parkgraph.com/api/v1";
|
|
11
|
+
|
|
12
|
+
/** A non-2xx answer from the API, or a request that could not reach it (status 0). */
|
|
13
|
+
export class ParkGraphError extends Error {
|
|
14
|
+
constructor(message, status, body = "", code = null, requestId = null) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = "ParkGraphError";
|
|
17
|
+
this.status = status;
|
|
18
|
+
this.body = body;
|
|
19
|
+
this.code = code;
|
|
20
|
+
this.requestId = requestId;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function errorFrom(status, text) {
|
|
25
|
+
let message = `API error ${status}`;
|
|
26
|
+
let code = null;
|
|
27
|
+
let requestId = null;
|
|
28
|
+
try {
|
|
29
|
+
const parsed = JSON.parse(text);
|
|
30
|
+
const err = parsed && typeof parsed === "object" ? parsed.error : null;
|
|
31
|
+
if (err && typeof err === "object") {
|
|
32
|
+
if (typeof err.message === "string" && err.message) message = err.message;
|
|
33
|
+
if (typeof err.code === "string") code = err.code;
|
|
34
|
+
if (typeof err.request_id === "string") requestId = err.request_id;
|
|
35
|
+
} else if (typeof err === "string" && err) {
|
|
36
|
+
message = err;
|
|
37
|
+
}
|
|
38
|
+
} catch {
|
|
39
|
+
// Not JSON: keep the generic message; the raw text is on `body`.
|
|
40
|
+
}
|
|
41
|
+
return new ParkGraphError(message, status, text, code, requestId);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function finiteNumber(name, value) {
|
|
45
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
46
|
+
throw new TypeError(`${name} must be a finite number`);
|
|
47
|
+
}
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export class ParkGraphClient {
|
|
52
|
+
#apiKey;
|
|
53
|
+
#baseUrl;
|
|
54
|
+
#fetch;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @param {{ apiKey?: string, baseUrl?: string, fetch?: typeof fetch }} [config]
|
|
58
|
+
* `apiKey` is optional: searchLots works without one. The other methods
|
|
59
|
+
* need a key and surface the API's 401 as a ParkGraphError.
|
|
60
|
+
*/
|
|
61
|
+
constructor(config = {}) {
|
|
62
|
+
const key = typeof config.apiKey === "string" ? config.apiKey.trim() : "";
|
|
63
|
+
this.#apiKey = key || undefined;
|
|
64
|
+
this.#baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
65
|
+
const f = config.fetch ?? globalThis.fetch;
|
|
66
|
+
if (typeof f !== "function") {
|
|
67
|
+
throw new TypeError("No fetch available: use Node.js 20+ or pass config.fetch");
|
|
68
|
+
}
|
|
69
|
+
this.#fetch = f;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async #request(path, init = {}) {
|
|
73
|
+
const headers = { Accept: "application/json" };
|
|
74
|
+
if (init.body !== undefined) headers["Content-Type"] = "application/json";
|
|
75
|
+
if (this.#apiKey) headers.Authorization = `Bearer ${this.#apiKey}`;
|
|
76
|
+
let res;
|
|
77
|
+
try {
|
|
78
|
+
res = await this.#fetch(`${this.#baseUrl}${path}`, { ...init, headers });
|
|
79
|
+
} catch (err) {
|
|
80
|
+
throw new ParkGraphError(`Could not reach Park Graph: ${err instanceof Error ? err.message : String(err)}`, 0);
|
|
81
|
+
}
|
|
82
|
+
const text = await res.text();
|
|
83
|
+
if (!res.ok) throw errorFrom(res.status, text);
|
|
84
|
+
try {
|
|
85
|
+
return JSON.parse(text);
|
|
86
|
+
} catch {
|
|
87
|
+
throw new ParkGraphError("Park Graph answered with something that is not JSON", res.status, text);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** GET /lots/search. Works without an API key. */
|
|
92
|
+
async searchLots(params) {
|
|
93
|
+
const qs = new URLSearchParams({
|
|
94
|
+
lat: String(finiteNumber("lat", params?.lat)),
|
|
95
|
+
lng: String(finiteNumber("lng", params?.lng)),
|
|
96
|
+
});
|
|
97
|
+
if (params.radius_km !== undefined) qs.set("radius_km", String(finiteNumber("radius_km", params.radius_km)));
|
|
98
|
+
if (params.limit !== undefined) qs.set("limit", String(finiteNumber("limit", params.limit)));
|
|
99
|
+
return this.#request(`/lots/search?${qs}`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** POST /sessions. */
|
|
103
|
+
async createSession(params) {
|
|
104
|
+
const body = { lot_id: params.lot_id };
|
|
105
|
+
if (params.plate !== undefined) body.plate = params.plate;
|
|
106
|
+
if (params.test_card !== undefined) body.test_card = params.test_card;
|
|
107
|
+
return this.#request("/sessions", { method: "POST", body: JSON.stringify(body) });
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** GET /sessions/{sessionId}. */
|
|
111
|
+
async getSession(sessionId) {
|
|
112
|
+
return this.#request(`/sessions/${encodeURIComponent(sessionId)}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** POST /sessions/end. */
|
|
116
|
+
async endSession(params) {
|
|
117
|
+
return this.#request("/sessions/end", {
|
|
118
|
+
method: "POST",
|
|
119
|
+
body: JSON.stringify({ session_id: params.session_id, session_code: params.session_code }),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** GET /health. */
|
|
124
|
+
async health() {
|
|
125
|
+
return this.#request("/health");
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export { ParkGraphClient as ParkGraph };
|
|
130
|
+
export default ParkGraphClient;
|
package/package.json
CHANGED
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parkgraph/agent-sdk",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.4.0",
|
|
4
|
+
"description": "Typed TypeScript client for the Park Graph parking API: search lots, book, check and end parking sessions from any agent framework.",
|
|
5
|
+
"homepage": "https://parkgraph.com/developers/sdk",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Park Graph (https://parkgraph.com)",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "./index.js",
|
|
10
|
+
"types": "./index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./index.d.ts",
|
|
14
|
+
"import": "./index.js"
|
|
15
|
+
},
|
|
16
|
+
"./package.json": "./package.json"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"index.js",
|
|
20
|
+
"index.d.ts",
|
|
21
|
+
"types.d.ts",
|
|
22
|
+
"README.md",
|
|
23
|
+
"CHANGELOG.md",
|
|
24
|
+
"LICENSE"
|
|
25
|
+
],
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=20"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"parking",
|
|
32
|
+
"park-graph",
|
|
33
|
+
"sdk",
|
|
34
|
+
"ai-agents",
|
|
35
|
+
"langchain",
|
|
36
|
+
"typescript"
|
|
37
|
+
]
|
|
38
|
+
}
|
package/types.d.ts
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
// Generated from agents/openai/openapi.yaml (Park Graph API 1.4.0) by lib/release/sdk-types.ts.
|
|
2
|
+
// Do not edit by hand: change the spec, then run `pnpm --filter @workspace/park-graph run sdk:types`.
|
|
3
|
+
|
|
4
|
+
export interface Lot {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
slug: string;
|
|
8
|
+
address: string;
|
|
9
|
+
city: string;
|
|
10
|
+
state: string;
|
|
11
|
+
/** Lot latitude (WGS 84). Lots without a valid point are left out of results. */
|
|
12
|
+
latitude: number;
|
|
13
|
+
/** Lot longitude (WGS 84). */
|
|
14
|
+
longitude: number;
|
|
15
|
+
/** Same as latitude, for map libraries. */
|
|
16
|
+
lat: number;
|
|
17
|
+
/** Same as longitude, for map libraries. */
|
|
18
|
+
lng: number;
|
|
19
|
+
total_spaces: number;
|
|
20
|
+
lot_type: "surface" | "garage" | "underground" | "rooftop" | "valet" | "street";
|
|
21
|
+
distance_km?: number;
|
|
22
|
+
/** Whether the lot owner has completed property verification */
|
|
23
|
+
verified?: boolean;
|
|
24
|
+
availability: {
|
|
25
|
+
total_spaces: number;
|
|
26
|
+
active_sessions: number;
|
|
27
|
+
available_spaces: number;
|
|
28
|
+
occupancy_pct: number;
|
|
29
|
+
is_full: boolean;
|
|
30
|
+
};
|
|
31
|
+
pricing: {
|
|
32
|
+
base_rate: number;
|
|
33
|
+
rate_unit: "hour" | "day" | "flat";
|
|
34
|
+
max_daily_rate: number | null;
|
|
35
|
+
currency: string;
|
|
36
|
+
} | null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface Health {
|
|
40
|
+
status: "ok" | "degraded" | "error";
|
|
41
|
+
/** The API (OpenAPI spec) version */
|
|
42
|
+
version: string;
|
|
43
|
+
commit?: string;
|
|
44
|
+
environment?: string;
|
|
45
|
+
timestamp?: string;
|
|
46
|
+
services?: Record<string, string>;
|
|
47
|
+
error?: ErrorBody;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface ErrorBody {
|
|
51
|
+
code?: string;
|
|
52
|
+
message?: string;
|
|
53
|
+
request_id?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The price the driver is charged, from the same engine as the driver page, reservations and agent tools. Amounts are integer cents (USD). */
|
|
57
|
+
export interface Quote {
|
|
58
|
+
duration_hours: number;
|
|
59
|
+
currency: string;
|
|
60
|
+
/** flat while a flat event price applies */
|
|
61
|
+
rate_unit: "hour" | "day" | "flat";
|
|
62
|
+
base_rate_cents: number;
|
|
63
|
+
/** Multiplier applied to the base rate (1 when no surge applies) */
|
|
64
|
+
multiplier: number;
|
|
65
|
+
effective_rate_cents: number;
|
|
66
|
+
max_daily_cents: number | null;
|
|
67
|
+
total_cents: number;
|
|
68
|
+
capped_at_daily_max: boolean;
|
|
69
|
+
surge: Surge;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Present while an event, Surge today or a dynamic rule raises the price (Pro and Enterprise lots only). */
|
|
73
|
+
export type Surge = {
|
|
74
|
+
active?: boolean;
|
|
75
|
+
/** The owner's event name, or "Surge active" */
|
|
76
|
+
label?: string;
|
|
77
|
+
kind?: "event" | "surge_today" | "busy_lot" | "peak" | "weekend" | "stacked";
|
|
78
|
+
multiplier?: number;
|
|
79
|
+
/** The owner's flat event price, when that is what applies */
|
|
80
|
+
event_price_cents?: number | null;
|
|
81
|
+
/** Which of the lot's limits held the price, if any */
|
|
82
|
+
bound?: "floor" | "cap" | "daily_max" | null;
|
|
83
|
+
description?: string;
|
|
84
|
+
} | null;
|
|
85
|
+
|
|
86
|
+
export interface Session {
|
|
87
|
+
id: string;
|
|
88
|
+
session_code: string;
|
|
89
|
+
short_code: string;
|
|
90
|
+
lot_id: string;
|
|
91
|
+
status: "active" | "completed" | "expired" | "cancelled";
|
|
92
|
+
started_at: string;
|
|
93
|
+
rate: number;
|
|
94
|
+
rate_unit: string;
|
|
95
|
+
estimated_amount: number;
|
|
96
|
+
quote: Quote;
|
|
97
|
+
payment_intent_id: string | null;
|
|
98
|
+
client_secret: string | null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface SessionDetail {
|
|
102
|
+
id: string;
|
|
103
|
+
session_code: string;
|
|
104
|
+
short_code: string;
|
|
105
|
+
lot_id: string;
|
|
106
|
+
vehicle_plate: string | null;
|
|
107
|
+
status: string;
|
|
108
|
+
started_at: string;
|
|
109
|
+
ended_at: string | null;
|
|
110
|
+
rate_at_start: number;
|
|
111
|
+
rate_unit: string;
|
|
112
|
+
effective_rate?: number;
|
|
113
|
+
subtotal?: number | null;
|
|
114
|
+
platform_fee?: number | null;
|
|
115
|
+
owner_payout?: number | null;
|
|
116
|
+
payment_status: string;
|
|
117
|
+
expected_end?: string | null;
|
|
118
|
+
extended_count?: number;
|
|
119
|
+
source?: string;
|
|
120
|
+
created_at?: string;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface SessionRefund {
|
|
124
|
+
/** The session's id (a UUID, or a sess_ id from /reserve/confirm). */
|
|
125
|
+
session_id?: string;
|
|
126
|
+
type?: "full" | "partial";
|
|
127
|
+
refunded_cents?: number;
|
|
128
|
+
fee_refunded_cents?: number;
|
|
129
|
+
owner_reversed_cents?: number;
|
|
130
|
+
replayed?: boolean;
|
|
131
|
+
payments?: Array<{
|
|
132
|
+
payment_intent_id?: string;
|
|
133
|
+
kind?: "session" | "extension";
|
|
134
|
+
amount_cents?: number;
|
|
135
|
+
fee_refunded_cents?: number;
|
|
136
|
+
owner_reversed_cents?: number;
|
|
137
|
+
refund_id?: string | null;
|
|
138
|
+
}>;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export interface SessionReceipt {
|
|
142
|
+
id: string;
|
|
143
|
+
status: string;
|
|
144
|
+
started_at: string;
|
|
145
|
+
ended_at: string;
|
|
146
|
+
duration_hours: number;
|
|
147
|
+
subtotal: number;
|
|
148
|
+
platform_fee: number;
|
|
149
|
+
owner_payout: number;
|
|
150
|
+
payment_status: string;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Query parameters of GET /lots/search. */
|
|
154
|
+
export interface SearchParkingParams {
|
|
155
|
+
/** Latitude of the search center */
|
|
156
|
+
lat: number;
|
|
157
|
+
/** Longitude of the search center */
|
|
158
|
+
lng: number;
|
|
159
|
+
/** Search radius in kilometers */
|
|
160
|
+
radius_km?: number;
|
|
161
|
+
/** Maximum results to return */
|
|
162
|
+
limit?: number;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** Successful response of GET /lots/search. */
|
|
166
|
+
export interface SearchParkingResponse {
|
|
167
|
+
lots: Array<Lot>;
|
|
168
|
+
/** One-line answer an assistant can quote. The MCP search_lots tool returns the same field. */
|
|
169
|
+
summary: string;
|
|
170
|
+
meta: {
|
|
171
|
+
lat: number;
|
|
172
|
+
lng: number;
|
|
173
|
+
radius_km: number;
|
|
174
|
+
count: number;
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** Successful response of GET /health. */
|
|
179
|
+
export type GetHealthResponse = Health;
|
|
180
|
+
|
|
181
|
+
/** JSON body of POST /sessions. */
|
|
182
|
+
export interface CreateSessionRequest {
|
|
183
|
+
/** Parking lot UUID from search results */
|
|
184
|
+
lot_id: string;
|
|
185
|
+
/** Vehicle license plate */
|
|
186
|
+
plate?: string;
|
|
187
|
+
/** Sandbox only (pk_test_ keys; a live key gets 400). The Stripe test card the authorization runs on, default 4242 4242 4242 4242. 4000 0000 0000 0002 answers 402 CARD_DECLINED; 4000 0000 0000 3220 creates the session with payment_status requires_action (3D Secure required). */
|
|
188
|
+
test_card?: "4242 4242 4242 4242" | "4000 0000 0000 0002" | "4000 0000 0000 3220";
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Successful response of POST /sessions. */
|
|
192
|
+
export interface CreateSessionResponse {
|
|
193
|
+
session: Session;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** Successful response of GET /sessions/{sessionId}. */
|
|
197
|
+
export interface GetSessionResponse {
|
|
198
|
+
session: SessionDetail;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** JSON body of POST /sessions/end. */
|
|
202
|
+
export interface EndSessionRequest {
|
|
203
|
+
/** Session UUID */
|
|
204
|
+
session_id: string;
|
|
205
|
+
/** Session code for verification */
|
|
206
|
+
session_code: string;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** Successful response of POST /sessions/end. */
|
|
210
|
+
export interface EndSessionResponse {
|
|
211
|
+
session: SessionReceipt;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** JSON body of POST /sessions/{sessionId}/refund. */
|
|
215
|
+
export interface RefundSessionRequest {
|
|
216
|
+
/** Cents to give back. Omit for a full refund. */
|
|
217
|
+
amount_cents?: number;
|
|
218
|
+
reason?: "requested_by_customer" | "duplicate" | "fraudulent";
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** Successful response of POST /sessions/{sessionId}/refund. */
|
|
222
|
+
export interface RefundSessionResponse {
|
|
223
|
+
refund?: SessionRefund;
|
|
224
|
+
}
|