@mortar-ai/skill 0.6.0 → 0.7.1
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/README.md +10 -5
- package/SKILL.md +49 -13
- package/manifest.json +3 -3
- package/package.json +1 -1
- package/references/architecture.md +1 -1
- package/references/control-plane.md +1 -1
- package/references/database.md +31 -0
- package/references/openapi.yaml +2942 -0
- package/references/schema-migrations.md +26 -7
|
@@ -0,0 +1,2942 @@
|
|
|
1
|
+
openapi: 3.0.3
|
|
2
|
+
info:
|
|
3
|
+
title: Mortar REST API
|
|
4
|
+
version: "0.2.1"
|
|
5
|
+
description: |
|
|
6
|
+
Backend-as-a-Service for mainland-China-friendly mobile and web apps.
|
|
7
|
+
|
|
8
|
+
This file is authoritative for every operation, request, response, error,
|
|
9
|
+
security rule, and trust-surface extension it documents, but it is not yet
|
|
10
|
+
an exhaustive route inventory. `internal/api/routes.go` remains authoritative
|
|
11
|
+
for route existence. AI code generation must use documented operations and
|
|
12
|
+
must not invent a missing contract merely because a route exists in code.
|
|
13
|
+
|
|
14
|
+
Project-scope paths in this document use the internal and backward-
|
|
15
|
+
compatible `/v1/{tenant}/...` form so generic OpenAPI tooling can supply a
|
|
16
|
+
path parameter on the apex server. The current SDK contract instead puts
|
|
17
|
+
the project UUID in the host and omits that path segment:
|
|
18
|
+
`https://<tenant>.api.mortar.appunvs.com/v1/...`. Do not combine both forms.
|
|
19
|
+
|
|
20
|
+
Two authentication schemes coexist:
|
|
21
|
+
* `AccountToken` — Account session JWT minted by
|
|
22
|
+
`/v1/_accounts/signin`, or an Account PAT (`mtr_pat_*`); scopes all
|
|
23
|
+
`/v1/_accounts/*` and project-lifecycle calls to one Mortar account.
|
|
24
|
+
* `APIKey` — Bearer token starting with `mtr_live_` (production) or
|
|
25
|
+
`mtr_test_` (sandbox); scopes a single project (its tenant_id) and one of
|
|
26
|
+
`admin` / `app` / `public` privilege tiers.
|
|
27
|
+
|
|
28
|
+
Signed-in project users may additionally send a User access JWT in
|
|
29
|
+
`X-Mortar-User-Token`. That optional identity layer is not modeled
|
|
30
|
+
consistently by every operation in this partial document.
|
|
31
|
+
|
|
32
|
+
Errors use a uniform `{ "error": "<machine_code>" }` body, occasionally
|
|
33
|
+
enriched with structured detail (see `tier_change_would_overflow`).
|
|
34
|
+
contact:
|
|
35
|
+
name: Mortar team
|
|
36
|
+
url: https://mortar.appunvs.com
|
|
37
|
+
servers:
|
|
38
|
+
- url: https://api.mortar.appunvs.com
|
|
39
|
+
description: Production apex for account routes and path-form project examples in this reference
|
|
40
|
+
- url: http://localhost:8080
|
|
41
|
+
description: Local development apex
|
|
42
|
+
|
|
43
|
+
x-mortar-ai-contract:
|
|
44
|
+
projectSourceOwner: fabric-harness-ai-turn
|
|
45
|
+
generatedSourceEndpoint: forbidden
|
|
46
|
+
defaultProjectCodeAccess: deny
|
|
47
|
+
description: |
|
|
48
|
+
Mortar publishes API contracts and live schema; it does not generate source
|
|
49
|
+
files for Fabric projects. Harness exposes only the operations relevant to a
|
|
50
|
+
turn, and the AI writes runtime-specific request, response, and application
|
|
51
|
+
types into ordinary project source. Operations marked projectCode: forbidden
|
|
52
|
+
are control-plane calls and must be reached only through their Harness tool.
|
|
53
|
+
|
|
54
|
+
tags:
|
|
55
|
+
- name: accounts
|
|
56
|
+
description: Mortar-account signup / signin / profile + project lifecycle.
|
|
57
|
+
- name: projects
|
|
58
|
+
description: Account-scope CRUD over the projects an account owns.
|
|
59
|
+
- name: auth
|
|
60
|
+
description: Per-project User registration and sessions.
|
|
61
|
+
- name: data
|
|
62
|
+
description: Per-project key/value tables + rows.
|
|
63
|
+
- name: storage
|
|
64
|
+
description: Per-project blob storage with optional signed-URL downloads.
|
|
65
|
+
- name: realtime
|
|
66
|
+
description: Server-Sent-Events stream of row changes for a given table.
|
|
67
|
+
- name: usage
|
|
68
|
+
description: Project credit balance + compute-spec caps surfaced by `mortar usage me` and embedded usage widgets.
|
|
69
|
+
- name: compute
|
|
70
|
+
description: Per-project serverless functions (deploy / delete / invoke / logs).
|
|
71
|
+
- name: payment
|
|
72
|
+
description: Top-up flow + provider webhooks (WeChat Pay, Alipay).
|
|
73
|
+
- name: admin
|
|
74
|
+
description: Project-scope admin operations (currently API key minting).
|
|
75
|
+
- name: health
|
|
76
|
+
description: Liveness / readiness / status probes (no auth).
|
|
77
|
+
- name: cron
|
|
78
|
+
description: Per-project scheduled function invocations.
|
|
79
|
+
- name: queue
|
|
80
|
+
description: Durable background-job queue (Postgres-backed).
|
|
81
|
+
- name: comms
|
|
82
|
+
description: Messaging primitive — transactional email + SMS, billed per message per channel.
|
|
83
|
+
- name: tokens
|
|
84
|
+
description: Account-scope Personal Access Tokens (PATs, format `mtr_pat_*`) for CI / headless use.
|
|
85
|
+
- name: domains
|
|
86
|
+
description: Account-scoped hostname claim and DNS verification only; custom-host routing and TLS provisioning are not implemented.
|
|
87
|
+
|
|
88
|
+
security:
|
|
89
|
+
- APIKey: []
|
|
90
|
+
- AccountToken: []
|
|
91
|
+
|
|
92
|
+
paths:
|
|
93
|
+
/health:
|
|
94
|
+
get:
|
|
95
|
+
tags: [health]
|
|
96
|
+
summary: Combined liveness + readiness probe.
|
|
97
|
+
security: []
|
|
98
|
+
responses:
|
|
99
|
+
"200":
|
|
100
|
+
description: Service is up.
|
|
101
|
+
"503":
|
|
102
|
+
description: A required dependency (DB or Redis) is unreachable.
|
|
103
|
+
|
|
104
|
+
/health/live:
|
|
105
|
+
get:
|
|
106
|
+
tags: [health]
|
|
107
|
+
summary: Process-level liveness — returns 200 if the binary can serve.
|
|
108
|
+
security: []
|
|
109
|
+
responses:
|
|
110
|
+
"200":
|
|
111
|
+
description: Alive.
|
|
112
|
+
|
|
113
|
+
/health/ready:
|
|
114
|
+
get:
|
|
115
|
+
tags: [health]
|
|
116
|
+
summary: Readiness — fails when DB or Redis aren't reachable.
|
|
117
|
+
security: []
|
|
118
|
+
responses:
|
|
119
|
+
"200":
|
|
120
|
+
description: Ready to serve.
|
|
121
|
+
"503":
|
|
122
|
+
description: Not ready.
|
|
123
|
+
|
|
124
|
+
/status:
|
|
125
|
+
get:
|
|
126
|
+
tags: [health]
|
|
127
|
+
summary: Human-readable HTML status page.
|
|
128
|
+
security: []
|
|
129
|
+
responses:
|
|
130
|
+
"200":
|
|
131
|
+
description: HTML status page.
|
|
132
|
+
|
|
133
|
+
/v1/_accounts/signup:
|
|
134
|
+
post:
|
|
135
|
+
tags: [accounts]
|
|
136
|
+
summary: Create a new Mortar account.
|
|
137
|
+
security: []
|
|
138
|
+
requestBody:
|
|
139
|
+
required: true
|
|
140
|
+
content:
|
|
141
|
+
application/json:
|
|
142
|
+
schema:
|
|
143
|
+
$ref: "#/components/schemas/AccountSignupRequest"
|
|
144
|
+
responses:
|
|
145
|
+
"200":
|
|
146
|
+
description: Account created; JWT issued.
|
|
147
|
+
content:
|
|
148
|
+
application/json:
|
|
149
|
+
schema:
|
|
150
|
+
$ref: "#/components/schemas/AccountTokenResponse"
|
|
151
|
+
"400":
|
|
152
|
+
$ref: "#/components/responses/BadRequest"
|
|
153
|
+
"409":
|
|
154
|
+
description: email_taken.
|
|
155
|
+
content:
|
|
156
|
+
application/json:
|
|
157
|
+
schema:
|
|
158
|
+
$ref: "#/components/schemas/Error"
|
|
159
|
+
|
|
160
|
+
/v1/_accounts/signin:
|
|
161
|
+
post:
|
|
162
|
+
tags: [accounts]
|
|
163
|
+
summary: Sign in to an existing Mortar account.
|
|
164
|
+
security: []
|
|
165
|
+
requestBody:
|
|
166
|
+
required: true
|
|
167
|
+
content:
|
|
168
|
+
application/json:
|
|
169
|
+
schema:
|
|
170
|
+
$ref: "#/components/schemas/AccountSigninRequest"
|
|
171
|
+
examples:
|
|
172
|
+
standard:
|
|
173
|
+
value:
|
|
174
|
+
email: dev@example.com
|
|
175
|
+
password: hunter2hunter2
|
|
176
|
+
responses:
|
|
177
|
+
"200":
|
|
178
|
+
description: Signed in.
|
|
179
|
+
content:
|
|
180
|
+
application/json:
|
|
181
|
+
schema:
|
|
182
|
+
$ref: "#/components/schemas/AccountTokenResponse"
|
|
183
|
+
examples:
|
|
184
|
+
ok:
|
|
185
|
+
value:
|
|
186
|
+
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
187
|
+
expires_at: "2026-05-20T10:30:00Z"
|
|
188
|
+
account:
|
|
189
|
+
id: acct_01HZ4
|
|
190
|
+
email: dev@example.com
|
|
191
|
+
name: Dev User
|
|
192
|
+
created_at: "2026-04-12T09:11:00Z"
|
|
193
|
+
"401":
|
|
194
|
+
description: invalid_credentials.
|
|
195
|
+
"403":
|
|
196
|
+
description: suspended.
|
|
197
|
+
|
|
198
|
+
/v1/_accounts/me:
|
|
199
|
+
get:
|
|
200
|
+
tags: [accounts]
|
|
201
|
+
summary: Return the current account's profile.
|
|
202
|
+
security:
|
|
203
|
+
- AccountToken: []
|
|
204
|
+
responses:
|
|
205
|
+
"200":
|
|
206
|
+
description: Profile.
|
|
207
|
+
content:
|
|
208
|
+
application/json:
|
|
209
|
+
schema:
|
|
210
|
+
$ref: "#/components/schemas/Account"
|
|
211
|
+
"401":
|
|
212
|
+
description: unauthorized.
|
|
213
|
+
"404":
|
|
214
|
+
description: not_found (account row missing).
|
|
215
|
+
|
|
216
|
+
/v1/_accounts/enterprise/contract:
|
|
217
|
+
get:
|
|
218
|
+
tags: [accounts]
|
|
219
|
+
summary: Return the authenticated Enterprise customer's logical capacity contract.
|
|
220
|
+
description: Physical cells, nodes, utilization, provider evidence, raw Mortar COGS, and publication operations are intentionally excluded.
|
|
221
|
+
security:
|
|
222
|
+
- AccountToken: []
|
|
223
|
+
responses:
|
|
224
|
+
"200":
|
|
225
|
+
description: Logical profiles, customer contract rates, and current admission availability.
|
|
226
|
+
content:
|
|
227
|
+
application/json:
|
|
228
|
+
schema:
|
|
229
|
+
$ref: "#/components/schemas/EnterpriseContract"
|
|
230
|
+
"403":
|
|
231
|
+
description: enterprise_subscription_required.
|
|
232
|
+
|
|
233
|
+
/v1/_accounts/notification-email/start:
|
|
234
|
+
post:
|
|
235
|
+
tags: [accounts]
|
|
236
|
+
summary: Send a verification code to an operational notification email.
|
|
237
|
+
description: The verified address receives account credential-expiry reminders; it does not replace the login email.
|
|
238
|
+
security:
|
|
239
|
+
- AccountToken: []
|
|
240
|
+
requestBody:
|
|
241
|
+
required: true
|
|
242
|
+
content:
|
|
243
|
+
application/json:
|
|
244
|
+
schema:
|
|
245
|
+
type: object
|
|
246
|
+
required: [email]
|
|
247
|
+
properties:
|
|
248
|
+
email:
|
|
249
|
+
type: string
|
|
250
|
+
format: email
|
|
251
|
+
responses:
|
|
252
|
+
"200":
|
|
253
|
+
description: Verification message accepted by the configured email provider.
|
|
254
|
+
"400":
|
|
255
|
+
description: invalid_body / invalid_email.
|
|
256
|
+
"429":
|
|
257
|
+
description: Verification send rate limit exceeded.
|
|
258
|
+
"502":
|
|
259
|
+
description: notification_email_delivery_failed.
|
|
260
|
+
"503":
|
|
261
|
+
description: notification_email_not_configured.
|
|
262
|
+
|
|
263
|
+
/v1/_accounts/notification-email/verify:
|
|
264
|
+
post:
|
|
265
|
+
tags: [accounts]
|
|
266
|
+
summary: Verify and bind the account's operational notification email.
|
|
267
|
+
security:
|
|
268
|
+
- AccountToken: []
|
|
269
|
+
requestBody:
|
|
270
|
+
required: true
|
|
271
|
+
content:
|
|
272
|
+
application/json:
|
|
273
|
+
schema:
|
|
274
|
+
type: object
|
|
275
|
+
required: [email, code]
|
|
276
|
+
properties:
|
|
277
|
+
email:
|
|
278
|
+
type: string
|
|
279
|
+
format: email
|
|
280
|
+
code:
|
|
281
|
+
type: string
|
|
282
|
+
pattern: "^[0-9]{6}$"
|
|
283
|
+
responses:
|
|
284
|
+
"200":
|
|
285
|
+
description: Address verified and bound.
|
|
286
|
+
"400":
|
|
287
|
+
description: invalid_verification_code / verification_code_expired.
|
|
288
|
+
"429":
|
|
289
|
+
description: verification_attempts_exhausted.
|
|
290
|
+
"503":
|
|
291
|
+
description: notification_email_not_configured.
|
|
292
|
+
|
|
293
|
+
/v1/_accounts/projects:
|
|
294
|
+
post:
|
|
295
|
+
tags: [projects]
|
|
296
|
+
summary: Create a new project.
|
|
297
|
+
security:
|
|
298
|
+
- AccountToken: []
|
|
299
|
+
requestBody:
|
|
300
|
+
required: true
|
|
301
|
+
content:
|
|
302
|
+
application/json:
|
|
303
|
+
schema:
|
|
304
|
+
$ref: "#/components/schemas/ProjectCreateRequest"
|
|
305
|
+
examples:
|
|
306
|
+
subscription_default:
|
|
307
|
+
value:
|
|
308
|
+
name: My App
|
|
309
|
+
credit_mode: hard_budget
|
|
310
|
+
responses:
|
|
311
|
+
"201":
|
|
312
|
+
description: Created.
|
|
313
|
+
content:
|
|
314
|
+
application/json:
|
|
315
|
+
schema:
|
|
316
|
+
$ref: "#/components/schemas/Project"
|
|
317
|
+
examples:
|
|
318
|
+
created:
|
|
319
|
+
value:
|
|
320
|
+
id: proj_01HZ4ABC
|
|
321
|
+
name: My App
|
|
322
|
+
compute_spec: nano
|
|
323
|
+
tier: nano
|
|
324
|
+
credit_mode: hard_budget
|
|
325
|
+
created_at: "2026-05-13T10:00:00Z"
|
|
326
|
+
"400":
|
|
327
|
+
$ref: "#/components/responses/BadRequest"
|
|
328
|
+
"401":
|
|
329
|
+
description: unauthorized.
|
|
330
|
+
"403":
|
|
331
|
+
description: compute_spec_not_available or active_project_limit_reached for the account subscription.
|
|
332
|
+
get:
|
|
333
|
+
tags: [projects]
|
|
334
|
+
summary: List the account's projects, newest first.
|
|
335
|
+
security:
|
|
336
|
+
- AccountToken: []
|
|
337
|
+
responses:
|
|
338
|
+
"200":
|
|
339
|
+
description: Project list.
|
|
340
|
+
content:
|
|
341
|
+
application/json:
|
|
342
|
+
schema:
|
|
343
|
+
type: object
|
|
344
|
+
properties:
|
|
345
|
+
projects:
|
|
346
|
+
type: array
|
|
347
|
+
items:
|
|
348
|
+
$ref: "#/components/schemas/Project"
|
|
349
|
+
"401":
|
|
350
|
+
description: unauthorized.
|
|
351
|
+
|
|
352
|
+
/v1/_accounts/projects/{id}:
|
|
353
|
+
parameters:
|
|
354
|
+
- $ref: "#/components/parameters/ProjectIDPath"
|
|
355
|
+
get:
|
|
356
|
+
tags: [projects]
|
|
357
|
+
summary: Fetch a single project by id.
|
|
358
|
+
security:
|
|
359
|
+
- AccountToken: []
|
|
360
|
+
responses:
|
|
361
|
+
"200":
|
|
362
|
+
description: Project.
|
|
363
|
+
content:
|
|
364
|
+
application/json:
|
|
365
|
+
schema:
|
|
366
|
+
$ref: "#/components/schemas/Project"
|
|
367
|
+
"404":
|
|
368
|
+
description: not_found (also returned for cross-account reads).
|
|
369
|
+
patch:
|
|
370
|
+
tags: [projects]
|
|
371
|
+
summary: Partial update (name, compute_spec, credit_mode, or Enterprise capacity_profile).
|
|
372
|
+
security:
|
|
373
|
+
- AccountToken: []
|
|
374
|
+
requestBody:
|
|
375
|
+
required: true
|
|
376
|
+
content:
|
|
377
|
+
application/json:
|
|
378
|
+
schema:
|
|
379
|
+
$ref: "#/components/schemas/ProjectUpdateRequest"
|
|
380
|
+
responses:
|
|
381
|
+
"200":
|
|
382
|
+
description: Updated.
|
|
383
|
+
content:
|
|
384
|
+
application/json:
|
|
385
|
+
schema:
|
|
386
|
+
$ref: "#/components/schemas/Project"
|
|
387
|
+
"400":
|
|
388
|
+
$ref: "#/components/responses/BadRequest"
|
|
389
|
+
"404":
|
|
390
|
+
description: not_found.
|
|
391
|
+
"409":
|
|
392
|
+
description: tier_change_would_overflow — see structured blockers.
|
|
393
|
+
content:
|
|
394
|
+
application/json:
|
|
395
|
+
schema:
|
|
396
|
+
$ref: "#/components/schemas/TierOverflow"
|
|
397
|
+
delete:
|
|
398
|
+
tags: [projects]
|
|
399
|
+
summary: Soft-delete a project (30-day retention).
|
|
400
|
+
security:
|
|
401
|
+
- AccountToken: []
|
|
402
|
+
responses:
|
|
403
|
+
"204":
|
|
404
|
+
description: Deleted.
|
|
405
|
+
"404":
|
|
406
|
+
description: not_found.
|
|
407
|
+
|
|
408
|
+
/v1/_accounts/projects/{id}/write-suspension:
|
|
409
|
+
parameters:
|
|
410
|
+
- $ref: "#/components/parameters/ProjectIDPath"
|
|
411
|
+
put:
|
|
412
|
+
tags: [projects]
|
|
413
|
+
summary: Suspend or resume tenant mutations for an owned Enterprise capacity-profile project.
|
|
414
|
+
security:
|
|
415
|
+
- AccountToken: []
|
|
416
|
+
requestBody:
|
|
417
|
+
required: true
|
|
418
|
+
content:
|
|
419
|
+
application/json:
|
|
420
|
+
schema:
|
|
421
|
+
$ref: "#/components/schemas/ProjectWriteSuspensionRequest"
|
|
422
|
+
responses:
|
|
423
|
+
"200":
|
|
424
|
+
description: Write state updated or already converged.
|
|
425
|
+
content:
|
|
426
|
+
application/json:
|
|
427
|
+
schema:
|
|
428
|
+
$ref: "#/components/schemas/ProjectWriteSuspension"
|
|
429
|
+
"400":
|
|
430
|
+
$ref: "#/components/responses/BadRequest"
|
|
431
|
+
"403":
|
|
432
|
+
description: enterprise_capacity_project_required.
|
|
433
|
+
"404":
|
|
434
|
+
description: not_found.
|
|
435
|
+
|
|
436
|
+
/v1/_accounts/projects/{id}/topup:
|
|
437
|
+
parameters:
|
|
438
|
+
- $ref: "#/components/parameters/ProjectIDPath"
|
|
439
|
+
post:
|
|
440
|
+
tags: [payment]
|
|
441
|
+
summary: Initiate a manual top-up via WeChat Pay or Alipay.
|
|
442
|
+
security:
|
|
443
|
+
- AccountToken: []
|
|
444
|
+
requestBody:
|
|
445
|
+
required: true
|
|
446
|
+
content:
|
|
447
|
+
application/json:
|
|
448
|
+
schema:
|
|
449
|
+
$ref: "#/components/schemas/TopupRequest"
|
|
450
|
+
examples:
|
|
451
|
+
wechat_50:
|
|
452
|
+
value:
|
|
453
|
+
provider: wechat_pay
|
|
454
|
+
amount_yuan: 50.0
|
|
455
|
+
responses:
|
|
456
|
+
"200":
|
|
457
|
+
description: Charge created — render QR or redirect the browser.
|
|
458
|
+
content:
|
|
459
|
+
application/json:
|
|
460
|
+
schema:
|
|
461
|
+
$ref: "#/components/schemas/ChargeResult"
|
|
462
|
+
examples:
|
|
463
|
+
wechat:
|
|
464
|
+
value:
|
|
465
|
+
provider: wechat_pay
|
|
466
|
+
external_ref: a1b2c3d4e5f6
|
|
467
|
+
qr_code_data: weixin://wxpay/bizpayurl?pr=AbCdEfG
|
|
468
|
+
expires_at_unix_sec: 1747130000
|
|
469
|
+
"400":
|
|
470
|
+
description: invalid_body / invalid_provider / amount_out_of_range.
|
|
471
|
+
"404":
|
|
472
|
+
description: not_found.
|
|
473
|
+
"502":
|
|
474
|
+
description: provider_call_failed.
|
|
475
|
+
"503":
|
|
476
|
+
description: provider_unavailable (no provider configured).
|
|
477
|
+
|
|
478
|
+
/v1/_webhooks/payment/{provider}:
|
|
479
|
+
parameters:
|
|
480
|
+
- name: provider
|
|
481
|
+
in: path
|
|
482
|
+
required: true
|
|
483
|
+
schema:
|
|
484
|
+
type: string
|
|
485
|
+
enum: [wechat_pay, alipay]
|
|
486
|
+
post:
|
|
487
|
+
tags: [payment]
|
|
488
|
+
summary: Provider webhook — signature-verified inline, no other auth.
|
|
489
|
+
security: []
|
|
490
|
+
requestBody:
|
|
491
|
+
required: true
|
|
492
|
+
content:
|
|
493
|
+
application/json:
|
|
494
|
+
schema:
|
|
495
|
+
$ref: "#/components/schemas/WebhookEvent"
|
|
496
|
+
responses:
|
|
497
|
+
"200":
|
|
498
|
+
description: Event accepted (idempotent; duplicates are no-ops).
|
|
499
|
+
"400":
|
|
500
|
+
description: verify_failed / no_project_id / read_body.
|
|
501
|
+
"404":
|
|
502
|
+
description: unknown_provider.
|
|
503
|
+
|
|
504
|
+
/v1/{tenant}/_admin/keys:
|
|
505
|
+
parameters:
|
|
506
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
507
|
+
post:
|
|
508
|
+
tags: [admin]
|
|
509
|
+
summary: Mint a new API key for the project (admin scope required).
|
|
510
|
+
security:
|
|
511
|
+
- APIKey: []
|
|
512
|
+
requestBody:
|
|
513
|
+
required: true
|
|
514
|
+
content:
|
|
515
|
+
application/json:
|
|
516
|
+
schema:
|
|
517
|
+
$ref: "#/components/schemas/APIKeyCreateRequest"
|
|
518
|
+
responses:
|
|
519
|
+
"201":
|
|
520
|
+
description: Key created — `raw_key` returned exactly once.
|
|
521
|
+
content:
|
|
522
|
+
application/json:
|
|
523
|
+
schema:
|
|
524
|
+
$ref: "#/components/schemas/APIKey"
|
|
525
|
+
"400":
|
|
526
|
+
description: invalid_body / name_required / invalid_scope.
|
|
527
|
+
"403":
|
|
528
|
+
description: admin_scope_required.
|
|
529
|
+
|
|
530
|
+
/v1/{tenant}/auth/signup:
|
|
531
|
+
parameters:
|
|
532
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
533
|
+
post:
|
|
534
|
+
tags: [auth]
|
|
535
|
+
summary: Create a User inside this project.
|
|
536
|
+
security:
|
|
537
|
+
- APIKey: []
|
|
538
|
+
requestBody:
|
|
539
|
+
required: true
|
|
540
|
+
content:
|
|
541
|
+
application/json:
|
|
542
|
+
schema:
|
|
543
|
+
$ref: "#/components/schemas/UserAuthRequest"
|
|
544
|
+
responses:
|
|
545
|
+
"201":
|
|
546
|
+
description: User created.
|
|
547
|
+
content:
|
|
548
|
+
application/json:
|
|
549
|
+
schema:
|
|
550
|
+
$ref: "#/components/schemas/UserAuthResponse"
|
|
551
|
+
"400":
|
|
552
|
+
description: invalid_body / email_invalid / password_too_short.
|
|
553
|
+
"409":
|
|
554
|
+
description: email_taken.
|
|
555
|
+
|
|
556
|
+
/v1/{tenant}/auth/signin:
|
|
557
|
+
parameters:
|
|
558
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
559
|
+
post:
|
|
560
|
+
tags: [auth]
|
|
561
|
+
summary: Sign in as a User.
|
|
562
|
+
security:
|
|
563
|
+
- APIKey: []
|
|
564
|
+
requestBody:
|
|
565
|
+
required: true
|
|
566
|
+
content:
|
|
567
|
+
application/json:
|
|
568
|
+
schema:
|
|
569
|
+
$ref: "#/components/schemas/UserAuthRequest"
|
|
570
|
+
responses:
|
|
571
|
+
"200":
|
|
572
|
+
description: Signed in.
|
|
573
|
+
content:
|
|
574
|
+
application/json:
|
|
575
|
+
schema:
|
|
576
|
+
$ref: "#/components/schemas/UserAuthResponse"
|
|
577
|
+
"401":
|
|
578
|
+
description: invalid_credentials.
|
|
579
|
+
|
|
580
|
+
/v1/{tenant}/auth/phone/start:
|
|
581
|
+
parameters:
|
|
582
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
583
|
+
post:
|
|
584
|
+
tags: [auth]
|
|
585
|
+
summary: Start phone-OTP login — cache a 6-digit code + send via comms.sms.
|
|
586
|
+
description: |
|
|
587
|
+
Composes the `comms` (sms) + `cache` primitives. Send-side throttle
|
|
588
|
+
is enforced (60s cooldown per recipient, 10/day per recipient,
|
|
589
|
+
200/day per tenant — see auth.md). Returns 200 even if the phone
|
|
590
|
+
is new — phone-OTP find-or-creates the User on verify.
|
|
591
|
+
security:
|
|
592
|
+
- APIKey: []
|
|
593
|
+
requestBody:
|
|
594
|
+
required: true
|
|
595
|
+
content:
|
|
596
|
+
application/json:
|
|
597
|
+
schema:
|
|
598
|
+
type: object
|
|
599
|
+
required: [phone]
|
|
600
|
+
properties:
|
|
601
|
+
phone:
|
|
602
|
+
type: string
|
|
603
|
+
description: E.164 phone (e.g. `+8613800138000`).
|
|
604
|
+
responses:
|
|
605
|
+
"200":
|
|
606
|
+
description: Code cached + SMS handed to the comms backend.
|
|
607
|
+
content:
|
|
608
|
+
application/json:
|
|
609
|
+
schema:
|
|
610
|
+
type: object
|
|
611
|
+
properties:
|
|
612
|
+
sent:
|
|
613
|
+
type: boolean
|
|
614
|
+
expires_in_sec:
|
|
615
|
+
type: integer
|
|
616
|
+
"400":
|
|
617
|
+
description: phone_invalid / invalid_body.
|
|
618
|
+
"429":
|
|
619
|
+
description: cooldown / daily_cap_recipient / daily_cap_tenant.
|
|
620
|
+
"503":
|
|
621
|
+
description: comms_not_configured.
|
|
622
|
+
|
|
623
|
+
/v1/{tenant}/auth/phone/verify:
|
|
624
|
+
parameters:
|
|
625
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
626
|
+
post:
|
|
627
|
+
tags: [auth]
|
|
628
|
+
summary: Verify the SMS code — find-or-create a User by phone, mint JWT.
|
|
629
|
+
security:
|
|
630
|
+
- APIKey: []
|
|
631
|
+
requestBody:
|
|
632
|
+
required: true
|
|
633
|
+
content:
|
|
634
|
+
application/json:
|
|
635
|
+
schema:
|
|
636
|
+
type: object
|
|
637
|
+
required: [phone, code]
|
|
638
|
+
properties:
|
|
639
|
+
phone:
|
|
640
|
+
type: string
|
|
641
|
+
code:
|
|
642
|
+
type: string
|
|
643
|
+
responses:
|
|
644
|
+
"200":
|
|
645
|
+
description: Code matched. User found-or-created, JWT issued.
|
|
646
|
+
content:
|
|
647
|
+
application/json:
|
|
648
|
+
schema:
|
|
649
|
+
$ref: "#/components/schemas/UserAuthResponse"
|
|
650
|
+
"401":
|
|
651
|
+
description: invalid_code (wrong or expired).
|
|
652
|
+
"429":
|
|
653
|
+
description: too_many_attempts (verify attempt cap hit — code invalidated).
|
|
654
|
+
|
|
655
|
+
/v1/{tenant}/auth/email/verify/start:
|
|
656
|
+
parameters:
|
|
657
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
658
|
+
post:
|
|
659
|
+
tags: [auth]
|
|
660
|
+
summary: Email a verification token to an existing User.
|
|
661
|
+
description: |
|
|
662
|
+
Always returns 200 — never reveals whether the email is registered.
|
|
663
|
+
Token TTL 15 min. Send-side throttle as above.
|
|
664
|
+
security:
|
|
665
|
+
- APIKey: []
|
|
666
|
+
requestBody:
|
|
667
|
+
required: true
|
|
668
|
+
content:
|
|
669
|
+
application/json:
|
|
670
|
+
schema:
|
|
671
|
+
type: object
|
|
672
|
+
required: [email]
|
|
673
|
+
properties:
|
|
674
|
+
email:
|
|
675
|
+
type: string
|
|
676
|
+
responses:
|
|
677
|
+
"200":
|
|
678
|
+
description: Sent (or silently no-op if no user).
|
|
679
|
+
"429":
|
|
680
|
+
description: cooldown / daily caps.
|
|
681
|
+
|
|
682
|
+
/v1/{tenant}/auth/email/verify/confirm:
|
|
683
|
+
parameters:
|
|
684
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
685
|
+
post:
|
|
686
|
+
tags: [auth]
|
|
687
|
+
summary: Confirm the token, set `email_verified=true` on the User.
|
|
688
|
+
security:
|
|
689
|
+
- APIKey: []
|
|
690
|
+
requestBody:
|
|
691
|
+
required: true
|
|
692
|
+
content:
|
|
693
|
+
application/json:
|
|
694
|
+
schema:
|
|
695
|
+
type: object
|
|
696
|
+
required: [email, token]
|
|
697
|
+
properties:
|
|
698
|
+
email:
|
|
699
|
+
type: string
|
|
700
|
+
token:
|
|
701
|
+
type: string
|
|
702
|
+
responses:
|
|
703
|
+
"200":
|
|
704
|
+
description: Marked verified (idempotent).
|
|
705
|
+
"401":
|
|
706
|
+
description: invalid_token.
|
|
707
|
+
"429":
|
|
708
|
+
description: too_many_attempts.
|
|
709
|
+
|
|
710
|
+
/v1/{tenant}/auth/password/reset/start:
|
|
711
|
+
parameters:
|
|
712
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
713
|
+
post:
|
|
714
|
+
tags: [auth]
|
|
715
|
+
summary: Email a password-reset token to an existing User.
|
|
716
|
+
description: |
|
|
717
|
+
Always returns 200 (no enumeration). Token TTL 30 min.
|
|
718
|
+
security:
|
|
719
|
+
- APIKey: []
|
|
720
|
+
requestBody:
|
|
721
|
+
required: true
|
|
722
|
+
content:
|
|
723
|
+
application/json:
|
|
724
|
+
schema:
|
|
725
|
+
type: object
|
|
726
|
+
required: [email]
|
|
727
|
+
properties:
|
|
728
|
+
email:
|
|
729
|
+
type: string
|
|
730
|
+
responses:
|
|
731
|
+
"200":
|
|
732
|
+
description: Sent (or silently no-op if no user).
|
|
733
|
+
"429":
|
|
734
|
+
description: cooldown / daily caps.
|
|
735
|
+
|
|
736
|
+
/v1/{tenant}/auth/password/reset/confirm:
|
|
737
|
+
parameters:
|
|
738
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
739
|
+
post:
|
|
740
|
+
tags: [auth]
|
|
741
|
+
summary: Consume the reset token, update the User's password hash.
|
|
742
|
+
security:
|
|
743
|
+
- APIKey: []
|
|
744
|
+
requestBody:
|
|
745
|
+
required: true
|
|
746
|
+
content:
|
|
747
|
+
application/json:
|
|
748
|
+
schema:
|
|
749
|
+
type: object
|
|
750
|
+
required: [email, token, new_password]
|
|
751
|
+
properties:
|
|
752
|
+
email:
|
|
753
|
+
type: string
|
|
754
|
+
token:
|
|
755
|
+
type: string
|
|
756
|
+
new_password:
|
|
757
|
+
type: string
|
|
758
|
+
description: New password (>=8 chars).
|
|
759
|
+
responses:
|
|
760
|
+
"200":
|
|
761
|
+
description: Password updated.
|
|
762
|
+
"400":
|
|
763
|
+
description: password_too_short / email_or_token_invalid.
|
|
764
|
+
"401":
|
|
765
|
+
description: invalid_token.
|
|
766
|
+
|
|
767
|
+
/v1/{tenant}/comms/send:
|
|
768
|
+
parameters:
|
|
769
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
770
|
+
post:
|
|
771
|
+
tags: [comms]
|
|
772
|
+
summary: Send one transactional message (email or sms) via the comms primitive.
|
|
773
|
+
description: |
|
|
774
|
+
Billed per message on the channel's resource (`email` or `sms`) in
|
|
775
|
+
the credit ledger. Aliyun SMS backends require a pre-registered
|
|
776
|
+
`template` code (模板报备).
|
|
777
|
+
security:
|
|
778
|
+
- APIKey: []
|
|
779
|
+
requestBody:
|
|
780
|
+
required: true
|
|
781
|
+
content:
|
|
782
|
+
application/json:
|
|
783
|
+
schema:
|
|
784
|
+
type: object
|
|
785
|
+
required: [channel, to]
|
|
786
|
+
properties:
|
|
787
|
+
channel:
|
|
788
|
+
type: string
|
|
789
|
+
enum: [email, sms]
|
|
790
|
+
to:
|
|
791
|
+
type: string
|
|
792
|
+
description: Email address (channel=email) or E.164 phone (channel=sms).
|
|
793
|
+
subject:
|
|
794
|
+
type: string
|
|
795
|
+
description: Email only.
|
|
796
|
+
body:
|
|
797
|
+
type: string
|
|
798
|
+
template:
|
|
799
|
+
type: string
|
|
800
|
+
description: Provider template code (REQUIRED by real SMS providers).
|
|
801
|
+
vars:
|
|
802
|
+
type: object
|
|
803
|
+
additionalProperties:
|
|
804
|
+
type: string
|
|
805
|
+
responses:
|
|
806
|
+
"201":
|
|
807
|
+
description: Accepted by the backend.
|
|
808
|
+
content:
|
|
809
|
+
application/json:
|
|
810
|
+
schema:
|
|
811
|
+
type: object
|
|
812
|
+
properties:
|
|
813
|
+
id:
|
|
814
|
+
type: string
|
|
815
|
+
channel:
|
|
816
|
+
type: string
|
|
817
|
+
to:
|
|
818
|
+
type: string
|
|
819
|
+
provider:
|
|
820
|
+
type: string
|
|
821
|
+
enum: [local, aliyun, tencent]
|
|
822
|
+
"400":
|
|
823
|
+
description: invalid_body / invalid_message.
|
|
824
|
+
"503":
|
|
825
|
+
description: comms_not_configured.
|
|
826
|
+
|
|
827
|
+
/v1/{tenant}/db/tables:
|
|
828
|
+
parameters:
|
|
829
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
830
|
+
post:
|
|
831
|
+
tags: [data]
|
|
832
|
+
operationId: createDatabaseTableLegacy
|
|
833
|
+
x-mortar-trust-surface: harness-control
|
|
834
|
+
x-mortar-project-code: forbidden
|
|
835
|
+
summary: Create a table.
|
|
836
|
+
security:
|
|
837
|
+
- APIKey: []
|
|
838
|
+
requestBody:
|
|
839
|
+
required: true
|
|
840
|
+
content:
|
|
841
|
+
application/json:
|
|
842
|
+
schema:
|
|
843
|
+
$ref: "#/components/schemas/TableCreateRequest"
|
|
844
|
+
responses:
|
|
845
|
+
"201":
|
|
846
|
+
description: Table created.
|
|
847
|
+
content:
|
|
848
|
+
application/json:
|
|
849
|
+
schema:
|
|
850
|
+
$ref: "#/components/schemas/Table"
|
|
851
|
+
"400":
|
|
852
|
+
description: invalid_body / name_required / column_name_required.
|
|
853
|
+
"409":
|
|
854
|
+
description: table_exists.
|
|
855
|
+
get:
|
|
856
|
+
tags: [data]
|
|
857
|
+
operationId: listDatabaseTables
|
|
858
|
+
x-mortar-trust-surface: app-runtime
|
|
859
|
+
x-mortar-project-code: allowed
|
|
860
|
+
summary: List tables in this project.
|
|
861
|
+
security:
|
|
862
|
+
- APIKey: []
|
|
863
|
+
responses:
|
|
864
|
+
"200":
|
|
865
|
+
description: Tables.
|
|
866
|
+
content:
|
|
867
|
+
application/json:
|
|
868
|
+
schema:
|
|
869
|
+
type: object
|
|
870
|
+
properties:
|
|
871
|
+
tables:
|
|
872
|
+
type: array
|
|
873
|
+
items:
|
|
874
|
+
$ref: "#/components/schemas/Table"
|
|
875
|
+
|
|
876
|
+
/v1/{tenant}/db/migrations/plan:
|
|
877
|
+
parameters:
|
|
878
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
879
|
+
post:
|
|
880
|
+
tags: [data]
|
|
881
|
+
operationId: planDatabaseMigration
|
|
882
|
+
x-mortar-trust-surface: harness-control
|
|
883
|
+
x-mortar-project-code: forbidden
|
|
884
|
+
summary: Parse exact versioned SQL into a typed execution plan without mutation.
|
|
885
|
+
description: |
|
|
886
|
+
Harness-only control operation behind `mortar_migrate`. Application code
|
|
887
|
+
must not call this endpoint or embed an app/admin credential for it.
|
|
888
|
+
security:
|
|
889
|
+
- APIKey: []
|
|
890
|
+
requestBody:
|
|
891
|
+
required: true
|
|
892
|
+
content:
|
|
893
|
+
application/json:
|
|
894
|
+
schema:
|
|
895
|
+
$ref: "#/components/schemas/MigrationPlanRequest"
|
|
896
|
+
responses:
|
|
897
|
+
"200":
|
|
898
|
+
description: Language-neutral plan, diagnostics, exact checksum, and current tenant schema revision.
|
|
899
|
+
content:
|
|
900
|
+
application/json:
|
|
901
|
+
schema:
|
|
902
|
+
$ref: "#/components/schemas/MigrationPlan"
|
|
903
|
+
"409":
|
|
904
|
+
description: The migration id is already recorded with different exact SQL bytes.
|
|
905
|
+
|
|
906
|
+
/v1/{tenant}/db/migrations/apply:
|
|
907
|
+
parameters:
|
|
908
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
909
|
+
post:
|
|
910
|
+
tags: [data]
|
|
911
|
+
operationId: applyDatabaseMigration
|
|
912
|
+
x-mortar-trust-surface: harness-control
|
|
913
|
+
x-mortar-project-code: forbidden
|
|
914
|
+
summary: Atomically apply a reviewed exact-SQL migration and record its revision.
|
|
915
|
+
description: |
|
|
916
|
+
Re-parses the exact SQL, verifies SHA-256 and expected_revision, locks
|
|
917
|
+
this tenant's schema revision, then commits every logical schema
|
|
918
|
+
operation and the ledger row in one PostgreSQL transaction. Retrying an
|
|
919
|
+
already-recorded migration_id + checksum is idempotent.
|
|
920
|
+
security:
|
|
921
|
+
- APIKey: []
|
|
922
|
+
requestBody:
|
|
923
|
+
required: true
|
|
924
|
+
content:
|
|
925
|
+
application/json:
|
|
926
|
+
schema:
|
|
927
|
+
$ref: "#/components/schemas/MigrationApplyRequest"
|
|
928
|
+
responses:
|
|
929
|
+
"200":
|
|
930
|
+
description: Applied or idempotently confirmed.
|
|
931
|
+
content:
|
|
932
|
+
application/json:
|
|
933
|
+
schema:
|
|
934
|
+
$ref: "#/components/schemas/MigrationApplyResponse"
|
|
935
|
+
"409":
|
|
936
|
+
description: Checksum or expected schema revision conflict.
|
|
937
|
+
"422":
|
|
938
|
+
description: The typed plan is not executable.
|
|
939
|
+
|
|
940
|
+
/v1/{tenant}/db/tables/{table}:
|
|
941
|
+
parameters:
|
|
942
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
943
|
+
- $ref: "#/components/parameters/TablePath"
|
|
944
|
+
delete:
|
|
945
|
+
tags: [data]
|
|
946
|
+
operationId: dropDatabaseTableLegacy
|
|
947
|
+
x-mortar-trust-surface: harness-control
|
|
948
|
+
x-mortar-project-code: forbidden
|
|
949
|
+
summary: Drop the table.
|
|
950
|
+
security:
|
|
951
|
+
- APIKey: []
|
|
952
|
+
responses:
|
|
953
|
+
"204":
|
|
954
|
+
description: Dropped.
|
|
955
|
+
|
|
956
|
+
/v1/{tenant}/db/transactions:
|
|
957
|
+
parameters:
|
|
958
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
959
|
+
post:
|
|
960
|
+
tags: [data]
|
|
961
|
+
operationId: executeDatabaseTransaction
|
|
962
|
+
x-mortar-trust-surface: trusted-server
|
|
963
|
+
x-mortar-project-code: trusted-server-only
|
|
964
|
+
summary: Atomically execute row writes and durable queue enqueues.
|
|
965
|
+
description: |
|
|
966
|
+
Runs every operation in one tenant-scoped PostgreSQL transaction. A
|
|
967
|
+
failure rolls back all preceding operations, including jobs inserted
|
|
968
|
+
into the PostgreSQL-backed queue. Requires an `app` or `admin` key;
|
|
969
|
+
object storage and other external providers are not part of this ACID
|
|
970
|
+
boundary. Maximum 200 operations and 1 MiB request body.
|
|
971
|
+
security:
|
|
972
|
+
- APIKey: []
|
|
973
|
+
requestBody:
|
|
974
|
+
required: true
|
|
975
|
+
content:
|
|
976
|
+
application/json:
|
|
977
|
+
schema:
|
|
978
|
+
$ref: "#/components/schemas/DBTransactionRequest"
|
|
979
|
+
responses:
|
|
980
|
+
"200":
|
|
981
|
+
description: Every operation committed.
|
|
982
|
+
content:
|
|
983
|
+
application/json:
|
|
984
|
+
schema:
|
|
985
|
+
$ref: "#/components/schemas/DBTransactionResponse"
|
|
986
|
+
"400":
|
|
987
|
+
description: Invalid operation or missing required fields; nothing committed.
|
|
988
|
+
"404":
|
|
989
|
+
description: An update target was not found; nothing committed.
|
|
990
|
+
"503":
|
|
991
|
+
description: transactional_queue_not_configured when an enqueue was requested.
|
|
992
|
+
|
|
993
|
+
/v1/{tenant}/db/tables/{table}/rows:
|
|
994
|
+
parameters:
|
|
995
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
996
|
+
- $ref: "#/components/parameters/TablePath"
|
|
997
|
+
post:
|
|
998
|
+
tags: [data]
|
|
999
|
+
operationId: insertDatabaseRows
|
|
1000
|
+
x-mortar-trust-surface: app-runtime
|
|
1001
|
+
x-mortar-project-code: allowed
|
|
1002
|
+
summary: Atomically insert or upsert one or more rows.
|
|
1003
|
+
description: |
|
|
1004
|
+
A batch is atomic, but this POST is not retry-safe by itself. The API
|
|
1005
|
+
provides no idempotency key or durable uniqueness constraint, and the
|
|
1006
|
+
SDK does not automatically retry it. Client-side in-flight guards only
|
|
1007
|
+
suppress duplicate interaction in that mounted client.
|
|
1008
|
+
security:
|
|
1009
|
+
- APIKey: []
|
|
1010
|
+
parameters:
|
|
1011
|
+
- name: upsert
|
|
1012
|
+
in: query
|
|
1013
|
+
description: When true, rows carrying an `id` replace that row; rows without an `id` insert.
|
|
1014
|
+
schema:
|
|
1015
|
+
type: boolean
|
|
1016
|
+
default: false
|
|
1017
|
+
requestBody:
|
|
1018
|
+
required: true
|
|
1019
|
+
content:
|
|
1020
|
+
application/json:
|
|
1021
|
+
schema:
|
|
1022
|
+
oneOf:
|
|
1023
|
+
- $ref: "#/components/schemas/RowBody"
|
|
1024
|
+
- $ref: "#/components/schemas/RowBatchBody"
|
|
1025
|
+
responses:
|
|
1026
|
+
"201":
|
|
1027
|
+
description: Inserted/upserted. Batch requests are all-or-nothing.
|
|
1028
|
+
content:
|
|
1029
|
+
application/json:
|
|
1030
|
+
schema:
|
|
1031
|
+
oneOf:
|
|
1032
|
+
- $ref: "#/components/schemas/Row"
|
|
1033
|
+
- $ref: "#/components/schemas/RowsResponse"
|
|
1034
|
+
"400":
|
|
1035
|
+
description: invalid_body / table_required / missing_required_fields.
|
|
1036
|
+
content:
|
|
1037
|
+
application/json:
|
|
1038
|
+
schema:
|
|
1039
|
+
$ref: "#/components/schemas/RowValidationError"
|
|
1040
|
+
get:
|
|
1041
|
+
tags: [data]
|
|
1042
|
+
operationId: listDatabaseRows
|
|
1043
|
+
x-mortar-trust-surface: app-runtime
|
|
1044
|
+
x-mortar-project-code: allowed
|
|
1045
|
+
summary: List rows; `?limit=N` (1..200, default 100).
|
|
1046
|
+
security:
|
|
1047
|
+
- APIKey: []
|
|
1048
|
+
parameters:
|
|
1049
|
+
- name: limit
|
|
1050
|
+
in: query
|
|
1051
|
+
schema:
|
|
1052
|
+
type: integer
|
|
1053
|
+
minimum: 1
|
|
1054
|
+
maximum: 200
|
|
1055
|
+
responses:
|
|
1056
|
+
"200":
|
|
1057
|
+
description: Rows.
|
|
1058
|
+
content:
|
|
1059
|
+
application/json:
|
|
1060
|
+
schema:
|
|
1061
|
+
$ref: "#/components/schemas/RowsResponse"
|
|
1062
|
+
patch:
|
|
1063
|
+
tags: [data]
|
|
1064
|
+
operationId: updateDatabaseRows
|
|
1065
|
+
x-mortar-trust-surface: app-runtime
|
|
1066
|
+
x-mortar-project-code: allowed
|
|
1067
|
+
summary: Atomically partial-update rows selected by query filters.
|
|
1068
|
+
description: |
|
|
1069
|
+
Accepts the same PostgREST-style filters, ordering, limit, and offset as
|
|
1070
|
+
GET. Matching rows are locked, partial-merged, validated, and updated in
|
|
1071
|
+
one PostgreSQL transaction (maximum 200 affected rows). Full-text
|
|
1072
|
+
search (`fts`) is rejected on mutation requests.
|
|
1073
|
+
security:
|
|
1074
|
+
- APIKey: []
|
|
1075
|
+
requestBody:
|
|
1076
|
+
required: true
|
|
1077
|
+
content:
|
|
1078
|
+
application/json:
|
|
1079
|
+
schema:
|
|
1080
|
+
$ref: "#/components/schemas/RowBody"
|
|
1081
|
+
responses:
|
|
1082
|
+
"200":
|
|
1083
|
+
description: Updated rows.
|
|
1084
|
+
content:
|
|
1085
|
+
application/json:
|
|
1086
|
+
schema:
|
|
1087
|
+
$ref: "#/components/schemas/RowsResponse"
|
|
1088
|
+
"400":
|
|
1089
|
+
description: Invalid filter/body or missing required fields; nothing updated.
|
|
1090
|
+
delete:
|
|
1091
|
+
tags: [data]
|
|
1092
|
+
operationId: deleteDatabaseRows
|
|
1093
|
+
x-mortar-trust-surface: app-runtime
|
|
1094
|
+
x-mortar-project-code: allowed
|
|
1095
|
+
summary: Atomically delete rows selected by query filters.
|
|
1096
|
+
description: |
|
|
1097
|
+
Accepts the same filters/order/limit/offset as GET. The returned rows
|
|
1098
|
+
are exactly the rows deleted in the single transaction (maximum 200).
|
|
1099
|
+
Full-text search (`fts`) is rejected on mutation requests.
|
|
1100
|
+
security:
|
|
1101
|
+
- APIKey: []
|
|
1102
|
+
responses:
|
|
1103
|
+
"200":
|
|
1104
|
+
description: Deleted rows.
|
|
1105
|
+
content:
|
|
1106
|
+
application/json:
|
|
1107
|
+
schema:
|
|
1108
|
+
$ref: "#/components/schemas/RowsResponse"
|
|
1109
|
+
|
|
1110
|
+
/v1/{tenant}/db/tables/{table}/rows/{id}:
|
|
1111
|
+
parameters:
|
|
1112
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
1113
|
+
- $ref: "#/components/parameters/TablePath"
|
|
1114
|
+
- name: id
|
|
1115
|
+
in: path
|
|
1116
|
+
required: true
|
|
1117
|
+
schema:
|
|
1118
|
+
type: string
|
|
1119
|
+
get:
|
|
1120
|
+
tags: [data]
|
|
1121
|
+
operationId: getDatabaseRow
|
|
1122
|
+
x-mortar-trust-surface: app-runtime
|
|
1123
|
+
x-mortar-project-code: allowed
|
|
1124
|
+
summary: Fetch one row.
|
|
1125
|
+
security:
|
|
1126
|
+
- APIKey: []
|
|
1127
|
+
responses:
|
|
1128
|
+
"200":
|
|
1129
|
+
description: Row.
|
|
1130
|
+
content:
|
|
1131
|
+
application/json:
|
|
1132
|
+
schema:
|
|
1133
|
+
$ref: "#/components/schemas/Row"
|
|
1134
|
+
"404":
|
|
1135
|
+
description: not_found.
|
|
1136
|
+
patch:
|
|
1137
|
+
tags: [data]
|
|
1138
|
+
operationId: updateDatabaseRow
|
|
1139
|
+
x-mortar-trust-surface: app-runtime
|
|
1140
|
+
x-mortar-project-code: allowed
|
|
1141
|
+
summary: Patch a row's `data` blob.
|
|
1142
|
+
security:
|
|
1143
|
+
- APIKey: []
|
|
1144
|
+
requestBody:
|
|
1145
|
+
required: true
|
|
1146
|
+
content:
|
|
1147
|
+
application/json:
|
|
1148
|
+
schema:
|
|
1149
|
+
$ref: "#/components/schemas/RowBody"
|
|
1150
|
+
responses:
|
|
1151
|
+
"200":
|
|
1152
|
+
description: Updated.
|
|
1153
|
+
content:
|
|
1154
|
+
application/json:
|
|
1155
|
+
schema:
|
|
1156
|
+
$ref: "#/components/schemas/Row"
|
|
1157
|
+
"400":
|
|
1158
|
+
description: invalid_body / table_and_id_required / missing_required_fields.
|
|
1159
|
+
content:
|
|
1160
|
+
application/json:
|
|
1161
|
+
schema:
|
|
1162
|
+
$ref: "#/components/schemas/RowValidationError"
|
|
1163
|
+
"404":
|
|
1164
|
+
description: not_found.
|
|
1165
|
+
delete:
|
|
1166
|
+
tags: [data]
|
|
1167
|
+
operationId: deleteDatabaseRow
|
|
1168
|
+
x-mortar-trust-surface: app-runtime
|
|
1169
|
+
x-mortar-project-code: allowed
|
|
1170
|
+
summary: Delete a row.
|
|
1171
|
+
security:
|
|
1172
|
+
- APIKey: []
|
|
1173
|
+
responses:
|
|
1174
|
+
"204":
|
|
1175
|
+
description: Deleted.
|
|
1176
|
+
|
|
1177
|
+
/v1/{tenant}/storage/files:
|
|
1178
|
+
parameters:
|
|
1179
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
1180
|
+
post:
|
|
1181
|
+
tags: [storage]
|
|
1182
|
+
summary: Upload a single object — body is the raw bytes.
|
|
1183
|
+
description: |
|
|
1184
|
+
`?bucket=` and `?key=` are required. `Content-Type` carries the
|
|
1185
|
+
MIME type (defaults to `application/octet-stream`). Max 50 MB per
|
|
1186
|
+
request. Uploads use immutable physical versions: PostgreSQL atomically
|
|
1187
|
+
switches the logical key only after the new bytes exist, while durable
|
|
1188
|
+
cleanup records reclaim failed uploads and replaced versions.
|
|
1189
|
+
security:
|
|
1190
|
+
- APIKey: []
|
|
1191
|
+
parameters:
|
|
1192
|
+
- name: bucket
|
|
1193
|
+
in: query
|
|
1194
|
+
required: true
|
|
1195
|
+
schema:
|
|
1196
|
+
type: string
|
|
1197
|
+
- name: key
|
|
1198
|
+
in: query
|
|
1199
|
+
required: true
|
|
1200
|
+
schema:
|
|
1201
|
+
type: string
|
|
1202
|
+
requestBody:
|
|
1203
|
+
required: true
|
|
1204
|
+
content:
|
|
1205
|
+
application/octet-stream:
|
|
1206
|
+
schema:
|
|
1207
|
+
type: string
|
|
1208
|
+
format: binary
|
|
1209
|
+
responses:
|
|
1210
|
+
"201":
|
|
1211
|
+
description: Uploaded.
|
|
1212
|
+
content:
|
|
1213
|
+
application/json:
|
|
1214
|
+
schema:
|
|
1215
|
+
$ref: "#/components/schemas/FileObject"
|
|
1216
|
+
examples:
|
|
1217
|
+
avatar:
|
|
1218
|
+
value:
|
|
1219
|
+
bucket: avatars
|
|
1220
|
+
key: users/u_123/main.png
|
|
1221
|
+
size_bytes: 24817
|
|
1222
|
+
content_type: image/png
|
|
1223
|
+
created_at: "2026-05-13T10:42:00Z"
|
|
1224
|
+
"400":
|
|
1225
|
+
description: bucket_and_key_required.
|
|
1226
|
+
"413":
|
|
1227
|
+
description: file_too_large (> 50 MB).
|
|
1228
|
+
get:
|
|
1229
|
+
tags: [storage]
|
|
1230
|
+
summary: List files (optionally filtered by `?bucket=`).
|
|
1231
|
+
security:
|
|
1232
|
+
- APIKey: []
|
|
1233
|
+
parameters:
|
|
1234
|
+
- name: bucket
|
|
1235
|
+
in: query
|
|
1236
|
+
schema:
|
|
1237
|
+
type: string
|
|
1238
|
+
responses:
|
|
1239
|
+
"200":
|
|
1240
|
+
description: Files.
|
|
1241
|
+
content:
|
|
1242
|
+
application/json:
|
|
1243
|
+
schema:
|
|
1244
|
+
type: object
|
|
1245
|
+
properties:
|
|
1246
|
+
files:
|
|
1247
|
+
type: array
|
|
1248
|
+
items:
|
|
1249
|
+
$ref: "#/components/schemas/FileObject"
|
|
1250
|
+
delete:
|
|
1251
|
+
tags: [storage]
|
|
1252
|
+
summary: Delete the object.
|
|
1253
|
+
description: Metadata deletion and a durable physical-cleanup record commit together; backend deletion is asynchronous and retried.
|
|
1254
|
+
security:
|
|
1255
|
+
- APIKey: []
|
|
1256
|
+
parameters:
|
|
1257
|
+
- name: bucket
|
|
1258
|
+
in: query
|
|
1259
|
+
required: true
|
|
1260
|
+
schema:
|
|
1261
|
+
type: string
|
|
1262
|
+
- name: key
|
|
1263
|
+
in: query
|
|
1264
|
+
required: true
|
|
1265
|
+
description: Full object key, may contain slashes.
|
|
1266
|
+
schema:
|
|
1267
|
+
type: string
|
|
1268
|
+
responses:
|
|
1269
|
+
"204":
|
|
1270
|
+
description: Deleted.
|
|
1271
|
+
|
|
1272
|
+
/v1/{tenant}/storage/sign/{bucket}/{key}:
|
|
1273
|
+
parameters:
|
|
1274
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
1275
|
+
- name: bucket
|
|
1276
|
+
in: path
|
|
1277
|
+
required: true
|
|
1278
|
+
schema:
|
|
1279
|
+
type: string
|
|
1280
|
+
- name: key
|
|
1281
|
+
in: path
|
|
1282
|
+
required: true
|
|
1283
|
+
schema:
|
|
1284
|
+
type: string
|
|
1285
|
+
- name: ttl_sec
|
|
1286
|
+
in: query
|
|
1287
|
+
description: TTL in seconds, clamped 60..86400; default 900.
|
|
1288
|
+
schema:
|
|
1289
|
+
type: integer
|
|
1290
|
+
minimum: 60
|
|
1291
|
+
maximum: 86400
|
|
1292
|
+
get:
|
|
1293
|
+
tags: [storage]
|
|
1294
|
+
summary: Mint a short-lived signed URL pointing at the backend.
|
|
1295
|
+
description: >-
|
|
1296
|
+
Authorizes direct object-store access and does not consume the project's
|
|
1297
|
+
API-concurrency budget. Signing is not proof of a download and does not
|
|
1298
|
+
create an object-egress charge; actual object egress is accounted only
|
|
1299
|
+
from provider-observed bytes.
|
|
1300
|
+
security:
|
|
1301
|
+
- APIKey: []
|
|
1302
|
+
responses:
|
|
1303
|
+
"200":
|
|
1304
|
+
description: Signed URL.
|
|
1305
|
+
content:
|
|
1306
|
+
application/json:
|
|
1307
|
+
schema:
|
|
1308
|
+
$ref: "#/components/schemas/SignedURL"
|
|
1309
|
+
"404":
|
|
1310
|
+
description: not_found.
|
|
1311
|
+
"501":
|
|
1312
|
+
description: backend_does_not_sign.
|
|
1313
|
+
|
|
1314
|
+
/v1/{tenant}/realtime/{table}:
|
|
1315
|
+
parameters:
|
|
1316
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
1317
|
+
- $ref: "#/components/parameters/TablePath"
|
|
1318
|
+
get:
|
|
1319
|
+
tags: [realtime]
|
|
1320
|
+
summary: SSE stream of row changes (`insert` / `update` / `delete`).
|
|
1321
|
+
security:
|
|
1322
|
+
- APIKey: []
|
|
1323
|
+
responses:
|
|
1324
|
+
"200":
|
|
1325
|
+
description: text/event-stream of change events.
|
|
1326
|
+
content:
|
|
1327
|
+
text/event-stream:
|
|
1328
|
+
schema:
|
|
1329
|
+
type: string
|
|
1330
|
+
"500":
|
|
1331
|
+
description: stream_not_supported (broker not wired).
|
|
1332
|
+
|
|
1333
|
+
/v1/{tenant}/usage/me:
|
|
1334
|
+
parameters:
|
|
1335
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
1336
|
+
get:
|
|
1337
|
+
tags: [usage]
|
|
1338
|
+
summary: Project's credit balance + compute-spec caps (surfaced by `mortar usage me`).
|
|
1339
|
+
security:
|
|
1340
|
+
- APIKey: []
|
|
1341
|
+
responses:
|
|
1342
|
+
"200":
|
|
1343
|
+
description: Usage summary.
|
|
1344
|
+
content:
|
|
1345
|
+
application/json:
|
|
1346
|
+
schema:
|
|
1347
|
+
$ref: "#/components/schemas/UsageSummary"
|
|
1348
|
+
examples:
|
|
1349
|
+
nano_in_use:
|
|
1350
|
+
value:
|
|
1351
|
+
project_id: proj_01HZ4ABC
|
|
1352
|
+
billing_period: "2026-05"
|
|
1353
|
+
compute_spec: nano
|
|
1354
|
+
tier: nano
|
|
1355
|
+
credit_mode: hard_budget
|
|
1356
|
+
credit:
|
|
1357
|
+
granted_yuan: 99.0
|
|
1358
|
+
used_yuan: 12.34
|
|
1359
|
+
balance_yuan: 86.66
|
|
1360
|
+
used_by_resource:
|
|
1361
|
+
storage: 1.24
|
|
1362
|
+
network_egress: 7.00
|
|
1363
|
+
function: 4.10
|
|
1364
|
+
compute_spec_caps:
|
|
1365
|
+
capacity_units: 1
|
|
1366
|
+
compute_vcpu_slot: 0.05
|
|
1367
|
+
db_ram_gb: 1.0
|
|
1368
|
+
db_disk_gb: 10.0
|
|
1369
|
+
db_max_conns: 60
|
|
1370
|
+
cache_ram_mb: 64.0
|
|
1371
|
+
storage_gb: 10.0
|
|
1372
|
+
network_gb_per_month: 25.0
|
|
1373
|
+
function_cpu_min_per_month: 200
|
|
1374
|
+
log_ingest_gb_per_month: 1
|
|
1375
|
+
baseline_yuan_per_hour: 0.010011
|
|
1376
|
+
monthly_fee_yuan: 0
|
|
1377
|
+
reference_monthly_list_price_yuan: 28
|
|
1378
|
+
pricing_policy_version: 2026-08-cell-100pct-markup-300-nearest8-v4
|
|
1379
|
+
"404":
|
|
1380
|
+
description: not_found.
|
|
1381
|
+
|
|
1382
|
+
/v1/{tenant}/compute/functions/{name}:
|
|
1383
|
+
parameters:
|
|
1384
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
1385
|
+
- $ref: "#/components/parameters/FunctionNamePath"
|
|
1386
|
+
post:
|
|
1387
|
+
tags: [compute]
|
|
1388
|
+
summary: Deploy (or overwrite) a function. Max source 256 KB.
|
|
1389
|
+
security:
|
|
1390
|
+
- APIKey: []
|
|
1391
|
+
requestBody:
|
|
1392
|
+
required: true
|
|
1393
|
+
content:
|
|
1394
|
+
application/json:
|
|
1395
|
+
schema:
|
|
1396
|
+
$ref: "#/components/schemas/FunctionDeployRequest"
|
|
1397
|
+
responses:
|
|
1398
|
+
"201":
|
|
1399
|
+
description: Deployed.
|
|
1400
|
+
content:
|
|
1401
|
+
application/json:
|
|
1402
|
+
schema:
|
|
1403
|
+
$ref: "#/components/schemas/FunctionView"
|
|
1404
|
+
"400":
|
|
1405
|
+
description: name_required / invalid_body / source_required.
|
|
1406
|
+
"413":
|
|
1407
|
+
description: source_too_large.
|
|
1408
|
+
"503":
|
|
1409
|
+
description: compute_not_configured.
|
|
1410
|
+
delete:
|
|
1411
|
+
tags: [compute]
|
|
1412
|
+
summary: Delete the function (idempotent).
|
|
1413
|
+
security:
|
|
1414
|
+
- APIKey: []
|
|
1415
|
+
responses:
|
|
1416
|
+
"204":
|
|
1417
|
+
description: Deleted.
|
|
1418
|
+
|
|
1419
|
+
/v1/{tenant}/compute/functions/{name}/invoke:
|
|
1420
|
+
parameters:
|
|
1421
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
1422
|
+
- $ref: "#/components/parameters/FunctionNamePath"
|
|
1423
|
+
post:
|
|
1424
|
+
tags: [compute]
|
|
1425
|
+
summary: Invoke the function (body is forwarded as the event).
|
|
1426
|
+
security:
|
|
1427
|
+
- APIKey: []
|
|
1428
|
+
requestBody:
|
|
1429
|
+
required: false
|
|
1430
|
+
content:
|
|
1431
|
+
application/json:
|
|
1432
|
+
schema:
|
|
1433
|
+
type: object
|
|
1434
|
+
additionalProperties: true
|
|
1435
|
+
responses:
|
|
1436
|
+
"200":
|
|
1437
|
+
description: Function response (shape function-defined).
|
|
1438
|
+
"503":
|
|
1439
|
+
description: compute_not_configured.
|
|
1440
|
+
get:
|
|
1441
|
+
tags: [compute]
|
|
1442
|
+
summary: Same as POST /invoke but for HTTP-GET-style triggers.
|
|
1443
|
+
security:
|
|
1444
|
+
- APIKey: []
|
|
1445
|
+
responses:
|
|
1446
|
+
"200":
|
|
1447
|
+
description: Function response.
|
|
1448
|
+
|
|
1449
|
+
/v1/{tenant}/compute/functions/{name}/logs:
|
|
1450
|
+
parameters:
|
|
1451
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
1452
|
+
- $ref: "#/components/parameters/FunctionNamePath"
|
|
1453
|
+
get:
|
|
1454
|
+
tags: [compute]
|
|
1455
|
+
summary: Tail recent log entries for the function.
|
|
1456
|
+
parameters:
|
|
1457
|
+
- name: since
|
|
1458
|
+
in: query
|
|
1459
|
+
schema: {type: integer, format: int64}
|
|
1460
|
+
description: Inclusive lower time bound in Unix milliseconds; defaults to ten minutes before until.
|
|
1461
|
+
- name: until
|
|
1462
|
+
in: query
|
|
1463
|
+
schema: {type: integer, format: int64}
|
|
1464
|
+
description: Upper time bound in Unix milliseconds; defaults to now.
|
|
1465
|
+
- name: limit
|
|
1466
|
+
in: query
|
|
1467
|
+
schema: {type: integer, minimum: 1, maximum: 1000, default: 100}
|
|
1468
|
+
- name: request
|
|
1469
|
+
in: query
|
|
1470
|
+
schema: {type: string}
|
|
1471
|
+
description: Provider invocation ID filter.
|
|
1472
|
+
security:
|
|
1473
|
+
- APIKey: []
|
|
1474
|
+
responses:
|
|
1475
|
+
"200":
|
|
1476
|
+
description: Entries.
|
|
1477
|
+
content:
|
|
1478
|
+
application/json:
|
|
1479
|
+
schema:
|
|
1480
|
+
type: object
|
|
1481
|
+
properties:
|
|
1482
|
+
entries:
|
|
1483
|
+
type: array
|
|
1484
|
+
items:
|
|
1485
|
+
$ref: "#/components/schemas/LogEntry"
|
|
1486
|
+
"503":
|
|
1487
|
+
description: Managed-log primitive is not configured.
|
|
1488
|
+
"502":
|
|
1489
|
+
description: log_query_failed.
|
|
1490
|
+
|
|
1491
|
+
/v1/{tenant}/cron/schedules:
|
|
1492
|
+
parameters:
|
|
1493
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
1494
|
+
post:
|
|
1495
|
+
tags: [cron]
|
|
1496
|
+
operationId: createCronSchedule
|
|
1497
|
+
summary: Create (or upsert) a cron schedule for a function.
|
|
1498
|
+
security:
|
|
1499
|
+
- APIKey: []
|
|
1500
|
+
requestBody:
|
|
1501
|
+
required: true
|
|
1502
|
+
content:
|
|
1503
|
+
application/json:
|
|
1504
|
+
schema:
|
|
1505
|
+
$ref: "#/components/schemas/CronScheduleCreateRequest"
|
|
1506
|
+
responses:
|
|
1507
|
+
"201":
|
|
1508
|
+
description: Schedule created or updated.
|
|
1509
|
+
content:
|
|
1510
|
+
application/json:
|
|
1511
|
+
schema:
|
|
1512
|
+
$ref: "#/components/schemas/CronSchedule"
|
|
1513
|
+
"400":
|
|
1514
|
+
description: invalid_body / fields_required / invalid_cron.
|
|
1515
|
+
get:
|
|
1516
|
+
tags: [cron]
|
|
1517
|
+
operationId: listCronSchedules
|
|
1518
|
+
summary: List all schedules in the tenant.
|
|
1519
|
+
security:
|
|
1520
|
+
- APIKey: []
|
|
1521
|
+
responses:
|
|
1522
|
+
"200":
|
|
1523
|
+
description: Schedules.
|
|
1524
|
+
content:
|
|
1525
|
+
application/json:
|
|
1526
|
+
schema:
|
|
1527
|
+
type: object
|
|
1528
|
+
properties:
|
|
1529
|
+
schedules:
|
|
1530
|
+
type: array
|
|
1531
|
+
items:
|
|
1532
|
+
$ref: "#/components/schemas/CronSchedule"
|
|
1533
|
+
|
|
1534
|
+
/v1/{tenant}/cron/schedules/{name}:
|
|
1535
|
+
parameters:
|
|
1536
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
1537
|
+
- name: name
|
|
1538
|
+
in: path
|
|
1539
|
+
required: true
|
|
1540
|
+
schema:
|
|
1541
|
+
type: string
|
|
1542
|
+
patch:
|
|
1543
|
+
tags: [cron]
|
|
1544
|
+
operationId: patchCronSchedule
|
|
1545
|
+
summary: Toggle the enabled flag on a schedule.
|
|
1546
|
+
security:
|
|
1547
|
+
- APIKey: []
|
|
1548
|
+
requestBody:
|
|
1549
|
+
required: true
|
|
1550
|
+
content:
|
|
1551
|
+
application/json:
|
|
1552
|
+
schema:
|
|
1553
|
+
$ref: "#/components/schemas/CronSchedulePatchRequest"
|
|
1554
|
+
responses:
|
|
1555
|
+
"204":
|
|
1556
|
+
description: Updated.
|
|
1557
|
+
"400":
|
|
1558
|
+
description: invalid_body / name_required / enabled_required.
|
|
1559
|
+
"404":
|
|
1560
|
+
description: not_found.
|
|
1561
|
+
delete:
|
|
1562
|
+
tags: [cron]
|
|
1563
|
+
operationId: deleteCronSchedule
|
|
1564
|
+
summary: Delete a schedule (idempotent).
|
|
1565
|
+
security:
|
|
1566
|
+
- APIKey: []
|
|
1567
|
+
responses:
|
|
1568
|
+
"204":
|
|
1569
|
+
description: Deleted.
|
|
1570
|
+
"400":
|
|
1571
|
+
description: name_required.
|
|
1572
|
+
|
|
1573
|
+
/v1/{tenant}/queue/jobs:
|
|
1574
|
+
parameters:
|
|
1575
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
1576
|
+
post:
|
|
1577
|
+
tags: [queue]
|
|
1578
|
+
operationId: enqueueJob
|
|
1579
|
+
summary: Enqueue a background job.
|
|
1580
|
+
security:
|
|
1581
|
+
- APIKey: []
|
|
1582
|
+
requestBody:
|
|
1583
|
+
required: true
|
|
1584
|
+
content:
|
|
1585
|
+
application/json:
|
|
1586
|
+
schema:
|
|
1587
|
+
$ref: "#/components/schemas/QueueEnqueueRequest"
|
|
1588
|
+
responses:
|
|
1589
|
+
"201":
|
|
1590
|
+
description: Created — server fills in id / status / timestamps.
|
|
1591
|
+
content:
|
|
1592
|
+
application/json:
|
|
1593
|
+
schema:
|
|
1594
|
+
$ref: "#/components/schemas/Job"
|
|
1595
|
+
"400":
|
|
1596
|
+
description: invalid_body / type_required / invalid_run_at.
|
|
1597
|
+
"503":
|
|
1598
|
+
description: queue_not_configured.
|
|
1599
|
+
get:
|
|
1600
|
+
tags: [queue]
|
|
1601
|
+
operationId: listJobs
|
|
1602
|
+
summary: List jobs in the tenant (filterable).
|
|
1603
|
+
security:
|
|
1604
|
+
- APIKey: []
|
|
1605
|
+
parameters:
|
|
1606
|
+
- name: type
|
|
1607
|
+
in: query
|
|
1608
|
+
schema:
|
|
1609
|
+
type: string
|
|
1610
|
+
- name: status
|
|
1611
|
+
in: query
|
|
1612
|
+
schema:
|
|
1613
|
+
type: string
|
|
1614
|
+
enum: [pending, running, completed, failed]
|
|
1615
|
+
- name: limit
|
|
1616
|
+
in: query
|
|
1617
|
+
schema:
|
|
1618
|
+
type: integer
|
|
1619
|
+
default: 50
|
|
1620
|
+
- name: offset
|
|
1621
|
+
in: query
|
|
1622
|
+
schema:
|
|
1623
|
+
type: integer
|
|
1624
|
+
default: 0
|
|
1625
|
+
responses:
|
|
1626
|
+
"200":
|
|
1627
|
+
description: Jobs page.
|
|
1628
|
+
content:
|
|
1629
|
+
application/json:
|
|
1630
|
+
schema:
|
|
1631
|
+
type: object
|
|
1632
|
+
properties:
|
|
1633
|
+
jobs:
|
|
1634
|
+
type: array
|
|
1635
|
+
items:
|
|
1636
|
+
$ref: "#/components/schemas/Job"
|
|
1637
|
+
"503":
|
|
1638
|
+
description: queue_not_configured.
|
|
1639
|
+
|
|
1640
|
+
/v1/{tenant}/queue/jobs/{id}:
|
|
1641
|
+
parameters:
|
|
1642
|
+
- $ref: "#/components/parameters/TenantPath"
|
|
1643
|
+
- name: id
|
|
1644
|
+
in: path
|
|
1645
|
+
required: true
|
|
1646
|
+
schema:
|
|
1647
|
+
type: string
|
|
1648
|
+
get:
|
|
1649
|
+
tags: [queue]
|
|
1650
|
+
operationId: getJob
|
|
1651
|
+
summary: Fetch one job by ID.
|
|
1652
|
+
security:
|
|
1653
|
+
- APIKey: []
|
|
1654
|
+
responses:
|
|
1655
|
+
"200":
|
|
1656
|
+
description: Job.
|
|
1657
|
+
content:
|
|
1658
|
+
application/json:
|
|
1659
|
+
schema:
|
|
1660
|
+
$ref: "#/components/schemas/Job"
|
|
1661
|
+
"400":
|
|
1662
|
+
description: id_required.
|
|
1663
|
+
"404":
|
|
1664
|
+
description: not_found.
|
|
1665
|
+
"503":
|
|
1666
|
+
description: queue_not_configured.
|
|
1667
|
+
|
|
1668
|
+
/v1/_accounts/tokens:
|
|
1669
|
+
post:
|
|
1670
|
+
tags: [tokens]
|
|
1671
|
+
operationId: createAccountToken
|
|
1672
|
+
summary: Mint a fixed-lived Personal Access Token (`mtr_pat_*`) for the current account.
|
|
1673
|
+
description: |
|
|
1674
|
+
Raw key is returned exactly ONCE in `raw_key`; subsequent reads only
|
|
1675
|
+
expose the prefix and metadata. Use the raw value as
|
|
1676
|
+
`Authorization: Bearer <raw_key>` against any account-scope endpoint
|
|
1677
|
+
— or as `MORTAR_ACCOUNT_TOKEN` env var for the CLI in CI / headless
|
|
1678
|
+
contexts. Every token has a fixed expiry. `expires_in_days` accepts
|
|
1679
|
+
1-365; omit / 0 selects the one-year default.
|
|
1680
|
+
security:
|
|
1681
|
+
- AccountToken: []
|
|
1682
|
+
requestBody:
|
|
1683
|
+
required: true
|
|
1684
|
+
content:
|
|
1685
|
+
application/json:
|
|
1686
|
+
schema:
|
|
1687
|
+
$ref: "#/components/schemas/AccountTokenCreateRequest"
|
|
1688
|
+
responses:
|
|
1689
|
+
"201":
|
|
1690
|
+
description: Token created. `raw_key` shown once.
|
|
1691
|
+
content:
|
|
1692
|
+
application/json:
|
|
1693
|
+
schema:
|
|
1694
|
+
$ref: "#/components/schemas/AccountTokenCreated"
|
|
1695
|
+
"400":
|
|
1696
|
+
description: invalid_body / name_required / invalid_token_expiry.
|
|
1697
|
+
get:
|
|
1698
|
+
tags: [tokens]
|
|
1699
|
+
operationId: listAccountTokens
|
|
1700
|
+
summary: List non-revoked PATs for the current account.
|
|
1701
|
+
security:
|
|
1702
|
+
- AccountToken: []
|
|
1703
|
+
responses:
|
|
1704
|
+
"200":
|
|
1705
|
+
description: Tokens.
|
|
1706
|
+
content:
|
|
1707
|
+
application/json:
|
|
1708
|
+
schema:
|
|
1709
|
+
type: object
|
|
1710
|
+
properties:
|
|
1711
|
+
tokens:
|
|
1712
|
+
type: array
|
|
1713
|
+
items:
|
|
1714
|
+
$ref: "#/components/schemas/AccountTokenView"
|
|
1715
|
+
|
|
1716
|
+
/v1/_accounts/tokens/{id}:
|
|
1717
|
+
parameters:
|
|
1718
|
+
- name: id
|
|
1719
|
+
in: path
|
|
1720
|
+
required: true
|
|
1721
|
+
schema:
|
|
1722
|
+
type: string
|
|
1723
|
+
delete:
|
|
1724
|
+
tags: [tokens]
|
|
1725
|
+
operationId: revokeAccountToken
|
|
1726
|
+
summary: Revoke a PAT. Idempotent.
|
|
1727
|
+
security:
|
|
1728
|
+
- AccountToken: []
|
|
1729
|
+
responses:
|
|
1730
|
+
"204":
|
|
1731
|
+
description: Revoked.
|
|
1732
|
+
"404":
|
|
1733
|
+
description: not_found (token doesn't exist or belongs to a different account).
|
|
1734
|
+
|
|
1735
|
+
/v1/_accounts/projects/{id}/domains:
|
|
1736
|
+
parameters:
|
|
1737
|
+
- $ref: "#/components/parameters/ProjectIDPath"
|
|
1738
|
+
post:
|
|
1739
|
+
tags: [domains]
|
|
1740
|
+
operationId: createCustomDomain
|
|
1741
|
+
summary: Claim a custom hostname; returns the TXT record to publish.
|
|
1742
|
+
security:
|
|
1743
|
+
- AccountToken: []
|
|
1744
|
+
requestBody:
|
|
1745
|
+
required: true
|
|
1746
|
+
content:
|
|
1747
|
+
application/json:
|
|
1748
|
+
schema:
|
|
1749
|
+
$ref: "#/components/schemas/CustomDomainCreateRequest"
|
|
1750
|
+
responses:
|
|
1751
|
+
"201":
|
|
1752
|
+
description: Claim created; publish TXT then call /verify.
|
|
1753
|
+
content:
|
|
1754
|
+
application/json:
|
|
1755
|
+
schema:
|
|
1756
|
+
$ref: "#/components/schemas/CustomDomain"
|
|
1757
|
+
"400":
|
|
1758
|
+
description: invalid_body / hostname_required / id_required.
|
|
1759
|
+
"403":
|
|
1760
|
+
description: forbidden.
|
|
1761
|
+
"404":
|
|
1762
|
+
description: not_found.
|
|
1763
|
+
"409":
|
|
1764
|
+
description: hostname_taken.
|
|
1765
|
+
get:
|
|
1766
|
+
tags: [domains]
|
|
1767
|
+
operationId: listCustomDomains
|
|
1768
|
+
summary: List custom domains attached to the project.
|
|
1769
|
+
security:
|
|
1770
|
+
- AccountToken: []
|
|
1771
|
+
responses:
|
|
1772
|
+
"200":
|
|
1773
|
+
description: Domains.
|
|
1774
|
+
content:
|
|
1775
|
+
application/json:
|
|
1776
|
+
schema:
|
|
1777
|
+
type: object
|
|
1778
|
+
properties:
|
|
1779
|
+
domains:
|
|
1780
|
+
type: array
|
|
1781
|
+
items:
|
|
1782
|
+
$ref: "#/components/schemas/CustomDomain"
|
|
1783
|
+
"403":
|
|
1784
|
+
description: forbidden.
|
|
1785
|
+
"404":
|
|
1786
|
+
description: not_found.
|
|
1787
|
+
|
|
1788
|
+
/v1/_accounts/projects/{id}/domains/{hostname}/verify:
|
|
1789
|
+
parameters:
|
|
1790
|
+
- $ref: "#/components/parameters/ProjectIDPath"
|
|
1791
|
+
- name: hostname
|
|
1792
|
+
in: path
|
|
1793
|
+
required: true
|
|
1794
|
+
schema:
|
|
1795
|
+
type: string
|
|
1796
|
+
post:
|
|
1797
|
+
tags: [domains]
|
|
1798
|
+
operationId: verifyCustomDomain
|
|
1799
|
+
summary: Verify ownership via DNS TXT lookup; stamp verified_at.
|
|
1800
|
+
security:
|
|
1801
|
+
- AccountToken: []
|
|
1802
|
+
responses:
|
|
1803
|
+
"200":
|
|
1804
|
+
description: Verified.
|
|
1805
|
+
content:
|
|
1806
|
+
application/json:
|
|
1807
|
+
schema:
|
|
1808
|
+
$ref: "#/components/schemas/CustomDomain"
|
|
1809
|
+
"400":
|
|
1810
|
+
description: hostname_required.
|
|
1811
|
+
"403":
|
|
1812
|
+
description: forbidden.
|
|
1813
|
+
"404":
|
|
1814
|
+
description: not_found.
|
|
1815
|
+
"412":
|
|
1816
|
+
description: txt_not_found (publish TXT then retry).
|
|
1817
|
+
"502":
|
|
1818
|
+
description: dns_lookup_failed.
|
|
1819
|
+
|
|
1820
|
+
/v1/_accounts/projects/{id}/domains/{hostname}:
|
|
1821
|
+
parameters:
|
|
1822
|
+
- $ref: "#/components/parameters/ProjectIDPath"
|
|
1823
|
+
- name: hostname
|
|
1824
|
+
in: path
|
|
1825
|
+
required: true
|
|
1826
|
+
schema:
|
|
1827
|
+
type: string
|
|
1828
|
+
delete:
|
|
1829
|
+
tags: [domains]
|
|
1830
|
+
operationId: deleteCustomDomain
|
|
1831
|
+
summary: Release a custom domain claim.
|
|
1832
|
+
security:
|
|
1833
|
+
- AccountToken: []
|
|
1834
|
+
responses:
|
|
1835
|
+
"204":
|
|
1836
|
+
description: Deleted.
|
|
1837
|
+
"400":
|
|
1838
|
+
description: hostname_required.
|
|
1839
|
+
"403":
|
|
1840
|
+
description: forbidden.
|
|
1841
|
+
"404":
|
|
1842
|
+
description: not_found.
|
|
1843
|
+
|
|
1844
|
+
components:
|
|
1845
|
+
securitySchemes:
|
|
1846
|
+
AccountToken:
|
|
1847
|
+
type: http
|
|
1848
|
+
scheme: bearer
|
|
1849
|
+
bearerFormat: JWT or mtr_pat_*
|
|
1850
|
+
description: |
|
|
1851
|
+
Account-scope auth for every `/v1/_accounts/*` route. Two token
|
|
1852
|
+
kinds are accepted in the same `Authorization: Bearer …` slot:
|
|
1853
|
+
the JWT minted by `/v1/_accounts/signin` (default-TTL session) and
|
|
1854
|
+
a fixed-lived Personal Access Token (`mtr_pat_*`) minted via
|
|
1855
|
+
`POST /v1/_accounts/tokens`. PATs are intended for CI / headless
|
|
1856
|
+
use and may be passed via the `MORTAR_ACCOUNT_TOKEN` env var to
|
|
1857
|
+
the `mortar` CLI.
|
|
1858
|
+
APIKey:
|
|
1859
|
+
type: http
|
|
1860
|
+
scheme: bearer
|
|
1861
|
+
bearerFormat: opaque
|
|
1862
|
+
description: |
|
|
1863
|
+
Project-scope API key starting with `mtr_live_` (production) or
|
|
1864
|
+
`mtr_test_` (sandbox). Bearer-encoded in `Authorization`.
|
|
1865
|
+
|
|
1866
|
+
parameters:
|
|
1867
|
+
TenantPath:
|
|
1868
|
+
name: tenant
|
|
1869
|
+
in: path
|
|
1870
|
+
required: true
|
|
1871
|
+
description: |
|
|
1872
|
+
Tenant ID — the data-isolation boundary. Its value is the
|
|
1873
|
+
project's UUID (the API-key's project; project = the tenant).
|
|
1874
|
+
schema:
|
|
1875
|
+
type: string
|
|
1876
|
+
ProjectIDPath:
|
|
1877
|
+
name: id
|
|
1878
|
+
in: path
|
|
1879
|
+
required: true
|
|
1880
|
+
schema:
|
|
1881
|
+
type: string
|
|
1882
|
+
TablePath:
|
|
1883
|
+
name: table
|
|
1884
|
+
in: path
|
|
1885
|
+
required: true
|
|
1886
|
+
schema:
|
|
1887
|
+
type: string
|
|
1888
|
+
FunctionNamePath:
|
|
1889
|
+
name: name
|
|
1890
|
+
in: path
|
|
1891
|
+
required: true
|
|
1892
|
+
schema:
|
|
1893
|
+
type: string
|
|
1894
|
+
|
|
1895
|
+
responses:
|
|
1896
|
+
BadRequest:
|
|
1897
|
+
description: Malformed request.
|
|
1898
|
+
content:
|
|
1899
|
+
application/json:
|
|
1900
|
+
schema:
|
|
1901
|
+
$ref: "#/components/schemas/Error"
|
|
1902
|
+
|
|
1903
|
+
schemas:
|
|
1904
|
+
Error:
|
|
1905
|
+
type: object
|
|
1906
|
+
required: [error]
|
|
1907
|
+
properties:
|
|
1908
|
+
error:
|
|
1909
|
+
type: string
|
|
1910
|
+
description: Machine-readable error code (e.g. `invalid_body`).
|
|
1911
|
+
detail:
|
|
1912
|
+
type: string
|
|
1913
|
+
|
|
1914
|
+
Account:
|
|
1915
|
+
type: object
|
|
1916
|
+
required: [id, email, subscription_plan, subscription_contract_only, allowed_compute_specs, max_active_projects, created_at]
|
|
1917
|
+
properties:
|
|
1918
|
+
id:
|
|
1919
|
+
type: string
|
|
1920
|
+
email:
|
|
1921
|
+
type: string
|
|
1922
|
+
format: email
|
|
1923
|
+
name:
|
|
1924
|
+
type: string
|
|
1925
|
+
subscription_plan:
|
|
1926
|
+
type: string
|
|
1927
|
+
enum: [free, pro, team, enterprise]
|
|
1928
|
+
subscription_valid_until:
|
|
1929
|
+
type: string
|
|
1930
|
+
format: date-time
|
|
1931
|
+
subscription_monthly_fee_yuan:
|
|
1932
|
+
type: number
|
|
1933
|
+
format: double
|
|
1934
|
+
subscription_compute_grant_yuan:
|
|
1935
|
+
type: number
|
|
1936
|
+
format: double
|
|
1937
|
+
subscription_settlement_kind:
|
|
1938
|
+
type: string
|
|
1939
|
+
enum: [online_payment, aggregate_invoice, contract_invoice]
|
|
1940
|
+
subscription_contract_only:
|
|
1941
|
+
type: boolean
|
|
1942
|
+
description: True for Enterprise; commercial terms are absent until an immutable contract period exists.
|
|
1943
|
+
allowed_compute_specs:
|
|
1944
|
+
type: array
|
|
1945
|
+
items:
|
|
1946
|
+
type: string
|
|
1947
|
+
enum: [nano, micro, small, medium, large, xl, 2xl, 4xl, 8xl, 16xl]
|
|
1948
|
+
max_active_projects:
|
|
1949
|
+
type: integer
|
|
1950
|
+
minimum: 0
|
|
1951
|
+
description: Account-level active-project ceiling; 0 means no catalog-level count ceiling.
|
|
1952
|
+
notification_email:
|
|
1953
|
+
type: string
|
|
1954
|
+
format: email
|
|
1955
|
+
description: Present only after proof of control.
|
|
1956
|
+
notification_email_verified_at:
|
|
1957
|
+
type: string
|
|
1958
|
+
format: date-time
|
|
1959
|
+
created_at:
|
|
1960
|
+
type: string
|
|
1961
|
+
format: date-time
|
|
1962
|
+
|
|
1963
|
+
AccountSignupRequest:
|
|
1964
|
+
type: object
|
|
1965
|
+
required: [email, password]
|
|
1966
|
+
properties:
|
|
1967
|
+
email:
|
|
1968
|
+
type: string
|
|
1969
|
+
format: email
|
|
1970
|
+
password:
|
|
1971
|
+
type: string
|
|
1972
|
+
minLength: 8
|
|
1973
|
+
name:
|
|
1974
|
+
type: string
|
|
1975
|
+
|
|
1976
|
+
AccountSigninRequest:
|
|
1977
|
+
type: object
|
|
1978
|
+
required: [email, password]
|
|
1979
|
+
properties:
|
|
1980
|
+
email:
|
|
1981
|
+
type: string
|
|
1982
|
+
password:
|
|
1983
|
+
type: string
|
|
1984
|
+
|
|
1985
|
+
AccountTokenResponse:
|
|
1986
|
+
type: object
|
|
1987
|
+
required: [token, expires_at, account]
|
|
1988
|
+
properties:
|
|
1989
|
+
token:
|
|
1990
|
+
type: string
|
|
1991
|
+
expires_at:
|
|
1992
|
+
type: string
|
|
1993
|
+
format: date-time
|
|
1994
|
+
account:
|
|
1995
|
+
$ref: "#/components/schemas/Account"
|
|
1996
|
+
|
|
1997
|
+
Project:
|
|
1998
|
+
type: object
|
|
1999
|
+
description: "A project has exactly one customer resource-spec axis: compute_spec for retail compute, or capacity_profile for an Enterprise capacity contract."
|
|
2000
|
+
required: [id, name, credit_mode, created_at]
|
|
2001
|
+
properties:
|
|
2002
|
+
id:
|
|
2003
|
+
type: string
|
|
2004
|
+
name:
|
|
2005
|
+
type: string
|
|
2006
|
+
compute_spec:
|
|
2007
|
+
type: string
|
|
2008
|
+
enum: [nano, micro, small, medium, large, xl, 2xl, 4xl, 8xl, 16xl]
|
|
2009
|
+
description: Retail compute specification; omitted when capacity_profile is present.
|
|
2010
|
+
tier:
|
|
2011
|
+
type: string
|
|
2012
|
+
enum: [nano, micro, small, medium, large, xl, 2xl, 4xl, 8xl, 16xl]
|
|
2013
|
+
deprecated: true
|
|
2014
|
+
description: Compatibility alias for compute_spec; omitted on Enterprise capacity projects.
|
|
2015
|
+
credit_mode:
|
|
2016
|
+
type: string
|
|
2017
|
+
enum: [hard_budget, post_pay]
|
|
2018
|
+
capacity_profile:
|
|
2019
|
+
type: string
|
|
2020
|
+
description: Logical profile on an Enterprise capacity project; mutually exclusive with compute_spec and tier.
|
|
2021
|
+
created_at:
|
|
2022
|
+
type: string
|
|
2023
|
+
format: date-time
|
|
2024
|
+
|
|
2025
|
+
ProjectCreateRequest:
|
|
2026
|
+
type: object
|
|
2027
|
+
required: [name]
|
|
2028
|
+
properties:
|
|
2029
|
+
name:
|
|
2030
|
+
type: string
|
|
2031
|
+
compute_spec:
|
|
2032
|
+
type: string
|
|
2033
|
+
enum: [nano, micro, small, medium, large, xl, 2xl, 4xl, 8xl, 16xl]
|
|
2034
|
+
tier:
|
|
2035
|
+
type: string
|
|
2036
|
+
enum: [nano, micro, small, medium, large, xl, 2xl, 4xl, 8xl, 16xl]
|
|
2037
|
+
deprecated: true
|
|
2038
|
+
credit_mode:
|
|
2039
|
+
type: string
|
|
2040
|
+
capacity_profile:
|
|
2041
|
+
type: string
|
|
2042
|
+
description: Enterprise only; mutually exclusive with compute_spec and tier.
|
|
2043
|
+
|
|
2044
|
+
ProjectUpdateRequest:
|
|
2045
|
+
type: object
|
|
2046
|
+
properties:
|
|
2047
|
+
name:
|
|
2048
|
+
type: string
|
|
2049
|
+
compute_spec:
|
|
2050
|
+
type: string
|
|
2051
|
+
enum: [nano, micro, small, medium, large, xl, 2xl, 4xl, 8xl, 16xl]
|
|
2052
|
+
tier:
|
|
2053
|
+
type: string
|
|
2054
|
+
enum: [nano, micro, small, medium, large, xl, 2xl, 4xl, 8xl, 16xl]
|
|
2055
|
+
deprecated: true
|
|
2056
|
+
credit_mode:
|
|
2057
|
+
type: string
|
|
2058
|
+
capacity_profile:
|
|
2059
|
+
type: string
|
|
2060
|
+
description: Enterprise only; changes the owned project's logical profile through Mortar admission. Mutually exclusive with compute_spec and tier; a placed capacity project cannot be changed through the retail compute_spec axis.
|
|
2061
|
+
|
|
2062
|
+
EnterpriseContract:
|
|
2063
|
+
type: object
|
|
2064
|
+
required: [generated_at, profiles, profile_rates, usage_rates, admission_open]
|
|
2065
|
+
properties:
|
|
2066
|
+
generated_at:
|
|
2067
|
+
type: string
|
|
2068
|
+
format: date-time
|
|
2069
|
+
profiles:
|
|
2070
|
+
type: array
|
|
2071
|
+
items:
|
|
2072
|
+
$ref: "#/components/schemas/EnterpriseCapacityProfile"
|
|
2073
|
+
profile_rate_version:
|
|
2074
|
+
type: string
|
|
2075
|
+
profile_rates:
|
|
2076
|
+
type: array
|
|
2077
|
+
items:
|
|
2078
|
+
$ref: "#/components/schemas/EnterpriseProfileRate"
|
|
2079
|
+
usage_rate_version:
|
|
2080
|
+
type: string
|
|
2081
|
+
usage_rates:
|
|
2082
|
+
type: array
|
|
2083
|
+
items:
|
|
2084
|
+
$ref: "#/components/schemas/EnterpriseUsageRate"
|
|
2085
|
+
admission_open:
|
|
2086
|
+
type: boolean
|
|
2087
|
+
|
|
2088
|
+
EnterpriseCapacityProfile:
|
|
2089
|
+
type: object
|
|
2090
|
+
required: [id, display_name, admission_units, max_api_concurrency, max_db_query_concurrency, max_realtime_connections, max_function_concurrency, hot_tenant_eligibility, security_isolation]
|
|
2091
|
+
properties:
|
|
2092
|
+
id: {type: string}
|
|
2093
|
+
display_name: {type: string}
|
|
2094
|
+
admission_units: {type: integer, format: int64}
|
|
2095
|
+
max_api_concurrency: {type: integer}
|
|
2096
|
+
max_db_query_concurrency: {type: integer}
|
|
2097
|
+
max_realtime_connections: {type: integer}
|
|
2098
|
+
max_function_concurrency: {type: integer}
|
|
2099
|
+
hot_tenant_eligibility: {type: string}
|
|
2100
|
+
security_isolation: {type: string}
|
|
2101
|
+
|
|
2102
|
+
EnterpriseProfileRate:
|
|
2103
|
+
type: object
|
|
2104
|
+
required: [profile_id, rate_version, hourly_rate_micros]
|
|
2105
|
+
properties:
|
|
2106
|
+
profile_id: {type: string}
|
|
2107
|
+
rate_version: {type: string}
|
|
2108
|
+
hourly_rate_micros: {type: integer, format: int64}
|
|
2109
|
+
|
|
2110
|
+
EnterpriseUsageRate:
|
|
2111
|
+
type: object
|
|
2112
|
+
required: [resource, native_unit, billing_unit, native_units_per_billing_unit, rate_micros_per_billing_unit]
|
|
2113
|
+
properties:
|
|
2114
|
+
resource: {type: string}
|
|
2115
|
+
native_unit: {type: string}
|
|
2116
|
+
billing_unit: {type: string}
|
|
2117
|
+
native_units_per_billing_unit: {type: number, format: double}
|
|
2118
|
+
rate_micros_per_billing_unit: {type: integer, format: int64}
|
|
2119
|
+
|
|
2120
|
+
ProjectWriteSuspensionRequest:
|
|
2121
|
+
type: object
|
|
2122
|
+
required: [suspended]
|
|
2123
|
+
properties:
|
|
2124
|
+
suspended:
|
|
2125
|
+
type: boolean
|
|
2126
|
+
reason:
|
|
2127
|
+
type: string
|
|
2128
|
+
minLength: 3
|
|
2129
|
+
maxLength: 200
|
|
2130
|
+
description: Required when suspended is true; ignored when resuming.
|
|
2131
|
+
|
|
2132
|
+
ProjectWriteSuspension:
|
|
2133
|
+
type: object
|
|
2134
|
+
required: [project_id, write_suspended, reason]
|
|
2135
|
+
properties:
|
|
2136
|
+
project_id:
|
|
2137
|
+
type: string
|
|
2138
|
+
write_suspended:
|
|
2139
|
+
type: boolean
|
|
2140
|
+
reason:
|
|
2141
|
+
type: string
|
|
2142
|
+
suspended_at:
|
|
2143
|
+
type: string
|
|
2144
|
+
format: date-time
|
|
2145
|
+
|
|
2146
|
+
TierOverflow:
|
|
2147
|
+
type: object
|
|
2148
|
+
properties:
|
|
2149
|
+
error:
|
|
2150
|
+
type: string
|
|
2151
|
+
example: tier_change_would_overflow
|
|
2152
|
+
target:
|
|
2153
|
+
type: string
|
|
2154
|
+
blockers:
|
|
2155
|
+
type: array
|
|
2156
|
+
items:
|
|
2157
|
+
type: object
|
|
2158
|
+
properties:
|
|
2159
|
+
resource:
|
|
2160
|
+
type: string
|
|
2161
|
+
current:
|
|
2162
|
+
type: integer
|
|
2163
|
+
format: int64
|
|
2164
|
+
new_limit:
|
|
2165
|
+
type: integer
|
|
2166
|
+
format: int64
|
|
2167
|
+
|
|
2168
|
+
TopupRequest:
|
|
2169
|
+
type: object
|
|
2170
|
+
required: [provider, amount_yuan]
|
|
2171
|
+
properties:
|
|
2172
|
+
provider:
|
|
2173
|
+
type: string
|
|
2174
|
+
enum: [wechat_pay, alipay]
|
|
2175
|
+
amount_yuan:
|
|
2176
|
+
type: number
|
|
2177
|
+
format: double
|
|
2178
|
+
minimum: 1.0
|
|
2179
|
+
maximum: 10000.0
|
|
2180
|
+
method:
|
|
2181
|
+
type: string
|
|
2182
|
+
description: Optional alipay sub-method (`scan` / `page`).
|
|
2183
|
+
|
|
2184
|
+
ChargeResult:
|
|
2185
|
+
type: object
|
|
2186
|
+
required: [provider, external_ref]
|
|
2187
|
+
properties:
|
|
2188
|
+
provider:
|
|
2189
|
+
type: string
|
|
2190
|
+
external_ref:
|
|
2191
|
+
type: string
|
|
2192
|
+
qr_code_data:
|
|
2193
|
+
type: string
|
|
2194
|
+
redirect_url:
|
|
2195
|
+
type: string
|
|
2196
|
+
expires_at_unix_sec:
|
|
2197
|
+
type: integer
|
|
2198
|
+
format: int64
|
|
2199
|
+
|
|
2200
|
+
WebhookEvent:
|
|
2201
|
+
type: object
|
|
2202
|
+
description: |
|
|
2203
|
+
Provider-shaped payload — the body is opaque to Mortar; the
|
|
2204
|
+
provider's `VerifyWebhook` parses + normalises it.
|
|
2205
|
+
additionalProperties: true
|
|
2206
|
+
|
|
2207
|
+
APIKeyCreateRequest:
|
|
2208
|
+
type: object
|
|
2209
|
+
required: [name]
|
|
2210
|
+
properties:
|
|
2211
|
+
name:
|
|
2212
|
+
type: string
|
|
2213
|
+
scope:
|
|
2214
|
+
type: string
|
|
2215
|
+
enum: [admin, app, public]
|
|
2216
|
+
default: app
|
|
2217
|
+
env:
|
|
2218
|
+
type: string
|
|
2219
|
+
enum: [live, test]
|
|
2220
|
+
default: live
|
|
2221
|
+
|
|
2222
|
+
APIKey:
|
|
2223
|
+
type: object
|
|
2224
|
+
required: [id, name, prefix, scope, raw_key, created_at]
|
|
2225
|
+
properties:
|
|
2226
|
+
id:
|
|
2227
|
+
type: string
|
|
2228
|
+
name:
|
|
2229
|
+
type: string
|
|
2230
|
+
prefix:
|
|
2231
|
+
type: string
|
|
2232
|
+
example: mtr_live_abcd
|
|
2233
|
+
scope:
|
|
2234
|
+
type: string
|
|
2235
|
+
enum: [admin, app, public]
|
|
2236
|
+
raw_key:
|
|
2237
|
+
type: string
|
|
2238
|
+
description: Full key, returned ONCE at creation time.
|
|
2239
|
+
created_at:
|
|
2240
|
+
type: string
|
|
2241
|
+
format: date-time
|
|
2242
|
+
|
|
2243
|
+
UserAuthRequest:
|
|
2244
|
+
type: object
|
|
2245
|
+
required: [email, password]
|
|
2246
|
+
properties:
|
|
2247
|
+
email:
|
|
2248
|
+
type: string
|
|
2249
|
+
format: email
|
|
2250
|
+
password:
|
|
2251
|
+
type: string
|
|
2252
|
+
minLength: 8
|
|
2253
|
+
|
|
2254
|
+
UserAuthResponse:
|
|
2255
|
+
type: object
|
|
2256
|
+
required: [access_token, user_id, expires_in_sec]
|
|
2257
|
+
properties:
|
|
2258
|
+
access_token:
|
|
2259
|
+
type: string
|
|
2260
|
+
refresh_token:
|
|
2261
|
+
type: string
|
|
2262
|
+
user_id:
|
|
2263
|
+
type: string
|
|
2264
|
+
email:
|
|
2265
|
+
type: string
|
|
2266
|
+
phone:
|
|
2267
|
+
type: string
|
|
2268
|
+
data_role:
|
|
2269
|
+
type: string
|
|
2270
|
+
enum: [user, admin]
|
|
2271
|
+
expires_in_sec:
|
|
2272
|
+
type: integer
|
|
2273
|
+
refresh_expires_in_sec:
|
|
2274
|
+
type: integer
|
|
2275
|
+
|
|
2276
|
+
TableColumn:
|
|
2277
|
+
type: object
|
|
2278
|
+
required: [name, type]
|
|
2279
|
+
properties:
|
|
2280
|
+
name:
|
|
2281
|
+
type: string
|
|
2282
|
+
type:
|
|
2283
|
+
type: string
|
|
2284
|
+
enum: [text, number, bool, json, timestamp, uuid]
|
|
2285
|
+
required:
|
|
2286
|
+
type: boolean
|
|
2287
|
+
|
|
2288
|
+
MigrationPlanRequest:
|
|
2289
|
+
type: object
|
|
2290
|
+
required: [migration_id, sql]
|
|
2291
|
+
properties:
|
|
2292
|
+
migration_id:
|
|
2293
|
+
type: string
|
|
2294
|
+
pattern: '^[0-9]{4,14}_[a-z0-9][a-z0-9_]*\.sql$'
|
|
2295
|
+
example: 0007_create_orders.sql
|
|
2296
|
+
sql:
|
|
2297
|
+
type: string
|
|
2298
|
+
description: Exact Mortar logical SQL bytes represented as a JSON string.
|
|
2299
|
+
|
|
2300
|
+
MigrationApplyRequest:
|
|
2301
|
+
allOf:
|
|
2302
|
+
- $ref: "#/components/schemas/MigrationPlanRequest"
|
|
2303
|
+
- type: object
|
|
2304
|
+
required: [checksum, expected_revision]
|
|
2305
|
+
properties:
|
|
2306
|
+
checksum:
|
|
2307
|
+
type: string
|
|
2308
|
+
pattern: '^sha256:[a-f0-9]{64}$'
|
|
2309
|
+
expected_revision:
|
|
2310
|
+
type: integer
|
|
2311
|
+
format: int64
|
|
2312
|
+
minimum: 0
|
|
2313
|
+
|
|
2314
|
+
MigrationOperation:
|
|
2315
|
+
type: object
|
|
2316
|
+
required: [kind, table]
|
|
2317
|
+
properties:
|
|
2318
|
+
kind:
|
|
2319
|
+
type: string
|
|
2320
|
+
enum: [create_table, drop_table, set_table_access, add_column, drop_column, create_index]
|
|
2321
|
+
table:
|
|
2322
|
+
type: string
|
|
2323
|
+
access:
|
|
2324
|
+
type: string
|
|
2325
|
+
enum: [private, public_read, public, public_insert, app_only]
|
|
2326
|
+
columns:
|
|
2327
|
+
type: array
|
|
2328
|
+
items:
|
|
2329
|
+
$ref: "#/components/schemas/TableColumn"
|
|
2330
|
+
column:
|
|
2331
|
+
type: string
|
|
2332
|
+
type:
|
|
2333
|
+
type: string
|
|
2334
|
+
enum: [text, number, bool, json, timestamp, uuid]
|
|
2335
|
+
required:
|
|
2336
|
+
type: boolean
|
|
2337
|
+
fields:
|
|
2338
|
+
type: array
|
|
2339
|
+
items:
|
|
2340
|
+
type: string
|
|
2341
|
+
|
|
2342
|
+
MigrationDiagnostic:
|
|
2343
|
+
type: object
|
|
2344
|
+
required: [severity, code, message]
|
|
2345
|
+
properties:
|
|
2346
|
+
severity:
|
|
2347
|
+
type: string
|
|
2348
|
+
enum: [warning, error]
|
|
2349
|
+
code:
|
|
2350
|
+
type: string
|
|
2351
|
+
message:
|
|
2352
|
+
type: string
|
|
2353
|
+
statement:
|
|
2354
|
+
type: integer
|
|
2355
|
+
|
|
2356
|
+
MigrationPlan:
|
|
2357
|
+
type: object
|
|
2358
|
+
required: [version, migration_id, checksum, current_revision, operations, diagnostics, destructive, executable]
|
|
2359
|
+
properties:
|
|
2360
|
+
version:
|
|
2361
|
+
type: string
|
|
2362
|
+
enum: [mortar.migration-plan.v1]
|
|
2363
|
+
migration_id:
|
|
2364
|
+
type: string
|
|
2365
|
+
checksum:
|
|
2366
|
+
type: string
|
|
2367
|
+
current_revision:
|
|
2368
|
+
type: integer
|
|
2369
|
+
format: int64
|
|
2370
|
+
operations:
|
|
2371
|
+
type: array
|
|
2372
|
+
items:
|
|
2373
|
+
$ref: "#/components/schemas/MigrationOperation"
|
|
2374
|
+
diagnostics:
|
|
2375
|
+
type: array
|
|
2376
|
+
items:
|
|
2377
|
+
$ref: "#/components/schemas/MigrationDiagnostic"
|
|
2378
|
+
destructive:
|
|
2379
|
+
type: boolean
|
|
2380
|
+
executable:
|
|
2381
|
+
type: boolean
|
|
2382
|
+
already_applied:
|
|
2383
|
+
type: boolean
|
|
2384
|
+
|
|
2385
|
+
MigrationApplyResponse:
|
|
2386
|
+
type: object
|
|
2387
|
+
required: [plan, revision, applied]
|
|
2388
|
+
properties:
|
|
2389
|
+
plan:
|
|
2390
|
+
$ref: "#/components/schemas/MigrationPlan"
|
|
2391
|
+
revision:
|
|
2392
|
+
type: integer
|
|
2393
|
+
format: int64
|
|
2394
|
+
applied:
|
|
2395
|
+
type: boolean
|
|
2396
|
+
|
|
2397
|
+
TableCreateRequest:
|
|
2398
|
+
type: object
|
|
2399
|
+
required: [name]
|
|
2400
|
+
properties:
|
|
2401
|
+
name:
|
|
2402
|
+
type: string
|
|
2403
|
+
columns:
|
|
2404
|
+
type: array
|
|
2405
|
+
items:
|
|
2406
|
+
type: object
|
|
2407
|
+
required: [name]
|
|
2408
|
+
properties:
|
|
2409
|
+
name:
|
|
2410
|
+
type: string
|
|
2411
|
+
type:
|
|
2412
|
+
type: string
|
|
2413
|
+
required:
|
|
2414
|
+
type: boolean
|
|
2415
|
+
|
|
2416
|
+
Table:
|
|
2417
|
+
type: object
|
|
2418
|
+
properties:
|
|
2419
|
+
name:
|
|
2420
|
+
type: string
|
|
2421
|
+
created_at:
|
|
2422
|
+
type: string
|
|
2423
|
+
format: date-time
|
|
2424
|
+
columns:
|
|
2425
|
+
type: array
|
|
2426
|
+
items:
|
|
2427
|
+
type: object
|
|
2428
|
+
properties:
|
|
2429
|
+
name:
|
|
2430
|
+
type: string
|
|
2431
|
+
type:
|
|
2432
|
+
type: string
|
|
2433
|
+
required:
|
|
2434
|
+
type: boolean
|
|
2435
|
+
|
|
2436
|
+
RowBody:
|
|
2437
|
+
type: object
|
|
2438
|
+
description: >
|
|
2439
|
+
Row insert / update envelope. The row's actual fields go under
|
|
2440
|
+
the `data` key — sending a flat body (e.g. `{"email": "..."}`
|
|
2441
|
+
directly) writes an empty row, because the server only reads
|
|
2442
|
+
the `data` property. `id`, `created_at`, and `updated_at` are
|
|
2443
|
+
server-owned metadata rather than application payload fields.
|
|
2444
|
+
required: [data]
|
|
2445
|
+
properties:
|
|
2446
|
+
data:
|
|
2447
|
+
type: object
|
|
2448
|
+
description: >
|
|
2449
|
+
The row's JSONB payload. Keys declared as `required: true`
|
|
2450
|
+
on the table (see TableCreateRequest) must be present and
|
|
2451
|
+
non-null, otherwise the server returns 400
|
|
2452
|
+
missing_required_fields. Logical type names inform AI-authored
|
|
2453
|
+
application types but are not runtime value validators. Do not
|
|
2454
|
+
send the server-owned `id`, `created_at`, or `updated_at` keys in
|
|
2455
|
+
ordinary insert/update payloads; documented upsert may use `id`
|
|
2456
|
+
only as row identity.
|
|
2457
|
+
additionalProperties: true
|
|
2458
|
+
|
|
2459
|
+
RowBatchBody:
|
|
2460
|
+
type: object
|
|
2461
|
+
required: [rows]
|
|
2462
|
+
properties:
|
|
2463
|
+
rows:
|
|
2464
|
+
type: array
|
|
2465
|
+
minItems: 1
|
|
2466
|
+
maxItems: 200
|
|
2467
|
+
items:
|
|
2468
|
+
type: object
|
|
2469
|
+
additionalProperties: true
|
|
2470
|
+
description: >
|
|
2471
|
+
All rows are inserted/upserted in one PostgreSQL transaction. Batch
|
|
2472
|
+
atomicity does not make retrying this POST idempotent. Each item is an
|
|
2473
|
+
application payload; omit server-owned `id`, `created_at`, and
|
|
2474
|
+
`updated_at` except that upsert may use `id` through its documented SDK
|
|
2475
|
+
contract.
|
|
2476
|
+
|
|
2477
|
+
Row:
|
|
2478
|
+
type: object
|
|
2479
|
+
description: >
|
|
2480
|
+
Stored row envelope. The SDK flattens the server-owned `id`,
|
|
2481
|
+
`created_at`, and `updated_at` metadata beside the application payload
|
|
2482
|
+
when it returns a row; those names are not application-owned fields.
|
|
2483
|
+
properties:
|
|
2484
|
+
id:
|
|
2485
|
+
type: string
|
|
2486
|
+
table:
|
|
2487
|
+
type: string
|
|
2488
|
+
data:
|
|
2489
|
+
type: object
|
|
2490
|
+
additionalProperties: true
|
|
2491
|
+
created_at:
|
|
2492
|
+
type: string
|
|
2493
|
+
format: date-time
|
|
2494
|
+
updated_at:
|
|
2495
|
+
type: string
|
|
2496
|
+
format: date-time
|
|
2497
|
+
|
|
2498
|
+
RowsResponse:
|
|
2499
|
+
type: object
|
|
2500
|
+
required: [rows]
|
|
2501
|
+
properties:
|
|
2502
|
+
rows:
|
|
2503
|
+
type: array
|
|
2504
|
+
items:
|
|
2505
|
+
$ref: "#/components/schemas/Row"
|
|
2506
|
+
|
|
2507
|
+
DBTransactionRequest:
|
|
2508
|
+
type: object
|
|
2509
|
+
required: [operations]
|
|
2510
|
+
properties:
|
|
2511
|
+
operations:
|
|
2512
|
+
type: array
|
|
2513
|
+
minItems: 1
|
|
2514
|
+
maxItems: 200
|
|
2515
|
+
items:
|
|
2516
|
+
$ref: "#/components/schemas/DBTransactionOperation"
|
|
2517
|
+
|
|
2518
|
+
DBTransactionOperation:
|
|
2519
|
+
type: object
|
|
2520
|
+
required: [op]
|
|
2521
|
+
description: |
|
|
2522
|
+
`insert`: table + data. `update`: table + UUID id + complete replacement
|
|
2523
|
+
data. `delete`: table + UUID id. `enqueue`: type plus optional payload,
|
|
2524
|
+
run_at, and max_attempts.
|
|
2525
|
+
properties:
|
|
2526
|
+
op:
|
|
2527
|
+
type: string
|
|
2528
|
+
enum: [insert, update, delete, enqueue]
|
|
2529
|
+
table:
|
|
2530
|
+
type: string
|
|
2531
|
+
id:
|
|
2532
|
+
type: string
|
|
2533
|
+
format: uuid
|
|
2534
|
+
data:
|
|
2535
|
+
type: object
|
|
2536
|
+
additionalProperties: true
|
|
2537
|
+
type:
|
|
2538
|
+
type: string
|
|
2539
|
+
payload: {}
|
|
2540
|
+
run_at:
|
|
2541
|
+
type: string
|
|
2542
|
+
format: date-time
|
|
2543
|
+
max_attempts:
|
|
2544
|
+
type: integer
|
|
2545
|
+
|
|
2546
|
+
DBTransactionResponse:
|
|
2547
|
+
type: object
|
|
2548
|
+
required: [results]
|
|
2549
|
+
properties:
|
|
2550
|
+
results:
|
|
2551
|
+
type: array
|
|
2552
|
+
items:
|
|
2553
|
+
type: object
|
|
2554
|
+
required: [op]
|
|
2555
|
+
properties:
|
|
2556
|
+
op:
|
|
2557
|
+
type: string
|
|
2558
|
+
row:
|
|
2559
|
+
$ref: "#/components/schemas/Row"
|
|
2560
|
+
job:
|
|
2561
|
+
$ref: "#/components/schemas/Job"
|
|
2562
|
+
|
|
2563
|
+
RowValidationError:
|
|
2564
|
+
type: object
|
|
2565
|
+
description: >
|
|
2566
|
+
Returned on 400 when the row body fails validation. `error` is
|
|
2567
|
+
the machine-readable code; `fields` (only for
|
|
2568
|
+
`missing_required_fields`) lists the column names that were
|
|
2569
|
+
absent / null.
|
|
2570
|
+
required: [error]
|
|
2571
|
+
properties:
|
|
2572
|
+
error:
|
|
2573
|
+
type: string
|
|
2574
|
+
enum:
|
|
2575
|
+
- invalid_body
|
|
2576
|
+
- table_required
|
|
2577
|
+
- table_and_id_required
|
|
2578
|
+
- missing_required_fields
|
|
2579
|
+
fields:
|
|
2580
|
+
type: array
|
|
2581
|
+
items:
|
|
2582
|
+
type: string
|
|
2583
|
+
|
|
2584
|
+
FileObject:
|
|
2585
|
+
type: object
|
|
2586
|
+
required: [bucket, key, size_bytes, content_type, created_at]
|
|
2587
|
+
properties:
|
|
2588
|
+
bucket:
|
|
2589
|
+
type: string
|
|
2590
|
+
key:
|
|
2591
|
+
type: string
|
|
2592
|
+
size_bytes:
|
|
2593
|
+
type: integer
|
|
2594
|
+
format: int64
|
|
2595
|
+
content_type:
|
|
2596
|
+
type: string
|
|
2597
|
+
created_at:
|
|
2598
|
+
type: string
|
|
2599
|
+
format: date-time
|
|
2600
|
+
|
|
2601
|
+
SignedURL:
|
|
2602
|
+
type: object
|
|
2603
|
+
properties:
|
|
2604
|
+
url:
|
|
2605
|
+
type: string
|
|
2606
|
+
expires_in_sec:
|
|
2607
|
+
type: integer
|
|
2608
|
+
format: int64
|
|
2609
|
+
size_bytes:
|
|
2610
|
+
type: integer
|
|
2611
|
+
format: int64
|
|
2612
|
+
description: Object metadata only; it is not a billed egress projection.
|
|
2613
|
+
|
|
2614
|
+
UsageSummary:
|
|
2615
|
+
type: object
|
|
2616
|
+
properties:
|
|
2617
|
+
project_id:
|
|
2618
|
+
type: string
|
|
2619
|
+
billing_period:
|
|
2620
|
+
type: string
|
|
2621
|
+
example: "2026-05"
|
|
2622
|
+
compute_spec:
|
|
2623
|
+
type: string
|
|
2624
|
+
tier:
|
|
2625
|
+
type: string
|
|
2626
|
+
deprecated: true
|
|
2627
|
+
credit_mode:
|
|
2628
|
+
type: string
|
|
2629
|
+
credit:
|
|
2630
|
+
type: object
|
|
2631
|
+
properties:
|
|
2632
|
+
granted_yuan:
|
|
2633
|
+
type: number
|
|
2634
|
+
used_yuan:
|
|
2635
|
+
type: number
|
|
2636
|
+
balance_yuan:
|
|
2637
|
+
type: number
|
|
2638
|
+
used_by_resource:
|
|
2639
|
+
type: object
|
|
2640
|
+
additionalProperties:
|
|
2641
|
+
type: number
|
|
2642
|
+
compute_spec_caps:
|
|
2643
|
+
type: object
|
|
2644
|
+
properties:
|
|
2645
|
+
capacity_units:
|
|
2646
|
+
type: integer
|
|
2647
|
+
format: int64
|
|
2648
|
+
compute_vcpu_slot:
|
|
2649
|
+
type: number
|
|
2650
|
+
description: vCPU share allocated to this tenant from the pool ECS.
|
|
2651
|
+
db_ram_gb:
|
|
2652
|
+
type: number
|
|
2653
|
+
db_disk_gb:
|
|
2654
|
+
type: number
|
|
2655
|
+
db_max_conns:
|
|
2656
|
+
type: integer
|
|
2657
|
+
cache_ram_mb:
|
|
2658
|
+
type: number
|
|
2659
|
+
storage_gb:
|
|
2660
|
+
type: number
|
|
2661
|
+
network_gb_per_month:
|
|
2662
|
+
type: number
|
|
2663
|
+
function_cpu_min_per_month:
|
|
2664
|
+
type: integer
|
|
2665
|
+
format: int64
|
|
2666
|
+
log_ingest_gb_per_month:
|
|
2667
|
+
type: number
|
|
2668
|
+
description: Hard cap for original uncompressed managed-log ingestion per month.
|
|
2669
|
+
baseline_yuan_per_hour:
|
|
2670
|
+
type: number
|
|
2671
|
+
description: Raw 100%-allocated Cell COGS before retail markup.
|
|
2672
|
+
monthly_fee_yuan:
|
|
2673
|
+
type: number
|
|
2674
|
+
description: Actual fixed fee charged for the current spec; Nano is zero-rated by Free.
|
|
2675
|
+
reference_monthly_list_price_yuan:
|
|
2676
|
+
type: number
|
|
2677
|
+
description: Cost-calibrated reference price before a plan inclusion such as Free Nano.
|
|
2678
|
+
pricing_policy_version:
|
|
2679
|
+
type: string
|
|
2680
|
+
tier_caps:
|
|
2681
|
+
deprecated: true
|
|
2682
|
+
description: Compatibility alias for compute_spec_caps.
|
|
2683
|
+
allOf:
|
|
2684
|
+
- $ref: "#/components/schemas/ComputeSpecCaps"
|
|
2685
|
+
|
|
2686
|
+
ComputeSpecCaps:
|
|
2687
|
+
type: object
|
|
2688
|
+
properties:
|
|
2689
|
+
capacity_units:
|
|
2690
|
+
type: integer
|
|
2691
|
+
format: int64
|
|
2692
|
+
compute_vcpu_slot:
|
|
2693
|
+
type: number
|
|
2694
|
+
db_ram_gb:
|
|
2695
|
+
type: number
|
|
2696
|
+
db_disk_gb:
|
|
2697
|
+
type: number
|
|
2698
|
+
db_max_conns:
|
|
2699
|
+
type: integer
|
|
2700
|
+
cache_ram_mb:
|
|
2701
|
+
type: number
|
|
2702
|
+
storage_gb:
|
|
2703
|
+
type: number
|
|
2704
|
+
network_gb_per_month:
|
|
2705
|
+
type: number
|
|
2706
|
+
function_cpu_min_per_month:
|
|
2707
|
+
type: integer
|
|
2708
|
+
format: int64
|
|
2709
|
+
log_ingest_gb_per_month:
|
|
2710
|
+
type: number
|
|
2711
|
+
description: Hard cap for original uncompressed managed-log ingestion per month.
|
|
2712
|
+
baseline_yuan_per_hour:
|
|
2713
|
+
type: number
|
|
2714
|
+
description: Raw 100%-allocated Cell COGS before retail markup.
|
|
2715
|
+
monthly_fee_yuan:
|
|
2716
|
+
type: number
|
|
2717
|
+
reference_monthly_list_price_yuan:
|
|
2718
|
+
type: number
|
|
2719
|
+
pricing_policy_version:
|
|
2720
|
+
type: string
|
|
2721
|
+
|
|
2722
|
+
FunctionDeployRequest:
|
|
2723
|
+
type: object
|
|
2724
|
+
required: [source]
|
|
2725
|
+
properties:
|
|
2726
|
+
runtime:
|
|
2727
|
+
type: string
|
|
2728
|
+
default: node
|
|
2729
|
+
source:
|
|
2730
|
+
type: string
|
|
2731
|
+
description: User code, max 256 KB.
|
|
2732
|
+
|
|
2733
|
+
FunctionView:
|
|
2734
|
+
type: object
|
|
2735
|
+
properties:
|
|
2736
|
+
name:
|
|
2737
|
+
type: string
|
|
2738
|
+
runtime:
|
|
2739
|
+
type: string
|
|
2740
|
+
|
|
2741
|
+
LogEntry:
|
|
2742
|
+
type: object
|
|
2743
|
+
required: [timestamp_ns, message]
|
|
2744
|
+
properties:
|
|
2745
|
+
timestamp_ns:
|
|
2746
|
+
type: integer
|
|
2747
|
+
format: int64
|
|
2748
|
+
description: Provider-canonical Unix timestamp in nanoseconds.
|
|
2749
|
+
message:
|
|
2750
|
+
type: string
|
|
2751
|
+
stream:
|
|
2752
|
+
type: string
|
|
2753
|
+
enum: [stdout, stderr, system]
|
|
2754
|
+
request_id:
|
|
2755
|
+
type: string
|
|
2756
|
+
description: Provider invocation ID when one is available.
|
|
2757
|
+
|
|
2758
|
+
Bundle:
|
|
2759
|
+
type: object
|
|
2760
|
+
description: |
|
|
2761
|
+
Reserved for future use — Mortar's compute primitive will expose
|
|
2762
|
+
deployed-bundle metadata here when the function-deploy path
|
|
2763
|
+
moves from inline source to a content-addressed bundle blob.
|
|
2764
|
+
properties:
|
|
2765
|
+
id:
|
|
2766
|
+
type: string
|
|
2767
|
+
sha256:
|
|
2768
|
+
type: string
|
|
2769
|
+
size_bytes:
|
|
2770
|
+
type: integer
|
|
2771
|
+
format: int64
|
|
2772
|
+
created_at:
|
|
2773
|
+
type: string
|
|
2774
|
+
format: date-time
|
|
2775
|
+
|
|
2776
|
+
CronScheduleCreateRequest:
|
|
2777
|
+
type: object
|
|
2778
|
+
required: [name, function_name, cron]
|
|
2779
|
+
properties:
|
|
2780
|
+
name:
|
|
2781
|
+
type: string
|
|
2782
|
+
description: Stable schedule identifier (unique within tenant).
|
|
2783
|
+
function_name:
|
|
2784
|
+
type: string
|
|
2785
|
+
description: Target compute function to invoke.
|
|
2786
|
+
cron:
|
|
2787
|
+
type: string
|
|
2788
|
+
description: Standard 5-field cron expression (UTC).
|
|
2789
|
+
example: "*/15 * * * *"
|
|
2790
|
+
enabled:
|
|
2791
|
+
type: boolean
|
|
2792
|
+
default: true
|
|
2793
|
+
|
|
2794
|
+
CronSchedulePatchRequest:
|
|
2795
|
+
type: object
|
|
2796
|
+
required: [enabled]
|
|
2797
|
+
properties:
|
|
2798
|
+
enabled:
|
|
2799
|
+
type: boolean
|
|
2800
|
+
|
|
2801
|
+
CronSchedule:
|
|
2802
|
+
type: object
|
|
2803
|
+
required: [name, function_name, cron, enabled, next_run_unix, last_run_unix]
|
|
2804
|
+
properties:
|
|
2805
|
+
name:
|
|
2806
|
+
type: string
|
|
2807
|
+
function_name:
|
|
2808
|
+
type: string
|
|
2809
|
+
cron:
|
|
2810
|
+
type: string
|
|
2811
|
+
enabled:
|
|
2812
|
+
type: boolean
|
|
2813
|
+
next_run_unix:
|
|
2814
|
+
type: integer
|
|
2815
|
+
format: int64
|
|
2816
|
+
last_run_unix:
|
|
2817
|
+
type: integer
|
|
2818
|
+
format: int64
|
|
2819
|
+
|
|
2820
|
+
QueueEnqueueRequest:
|
|
2821
|
+
type: object
|
|
2822
|
+
required: [type]
|
|
2823
|
+
properties:
|
|
2824
|
+
type:
|
|
2825
|
+
type: string
|
|
2826
|
+
description: Job-type identifier matched by the registered worker.
|
|
2827
|
+
payload:
|
|
2828
|
+
description: Opaque JSON forwarded to the handler.
|
|
2829
|
+
run_at:
|
|
2830
|
+
type: string
|
|
2831
|
+
format: date-time
|
|
2832
|
+
description: RFC3339 timestamp; omit/empty for "now".
|
|
2833
|
+
max_attempts:
|
|
2834
|
+
type: integer
|
|
2835
|
+
default: 3
|
|
2836
|
+
|
|
2837
|
+
Job:
|
|
2838
|
+
type: object
|
|
2839
|
+
required:
|
|
2840
|
+
[id, type, status, run_at, max_attempts, attempt_count, created_at, updated_at]
|
|
2841
|
+
properties:
|
|
2842
|
+
id:
|
|
2843
|
+
type: string
|
|
2844
|
+
type:
|
|
2845
|
+
type: string
|
|
2846
|
+
payload:
|
|
2847
|
+
description: Opaque JSON.
|
|
2848
|
+
status:
|
|
2849
|
+
type: string
|
|
2850
|
+
enum: [pending, running, completed, failed]
|
|
2851
|
+
run_at:
|
|
2852
|
+
type: string
|
|
2853
|
+
format: date-time
|
|
2854
|
+
max_attempts:
|
|
2855
|
+
type: integer
|
|
2856
|
+
attempt_count:
|
|
2857
|
+
type: integer
|
|
2858
|
+
last_error:
|
|
2859
|
+
type: string
|
|
2860
|
+
created_at:
|
|
2861
|
+
type: string
|
|
2862
|
+
format: date-time
|
|
2863
|
+
updated_at:
|
|
2864
|
+
type: string
|
|
2865
|
+
format: date-time
|
|
2866
|
+
|
|
2867
|
+
AccountTokenCreateRequest:
|
|
2868
|
+
type: object
|
|
2869
|
+
required: [name]
|
|
2870
|
+
properties:
|
|
2871
|
+
name:
|
|
2872
|
+
type: string
|
|
2873
|
+
description: Human-readable label (e.g. "ci-deploy").
|
|
2874
|
+
expires_in_days:
|
|
2875
|
+
type: integer
|
|
2876
|
+
minimum: 0
|
|
2877
|
+
maximum: 365
|
|
2878
|
+
description: Days until expiry; omit / 0 selects the one-year default. Values 1-365 choose a shorter fixed lifetime.
|
|
2879
|
+
|
|
2880
|
+
AccountTokenView:
|
|
2881
|
+
type: object
|
|
2882
|
+
required: [id, name, prefix, created_at, expires_at]
|
|
2883
|
+
properties:
|
|
2884
|
+
id:
|
|
2885
|
+
type: string
|
|
2886
|
+
name:
|
|
2887
|
+
type: string
|
|
2888
|
+
prefix:
|
|
2889
|
+
type: string
|
|
2890
|
+
description: First 12 chars (e.g. `mtr_pat_a1bc`) — indexed lookup handle, safe to log.
|
|
2891
|
+
created_at:
|
|
2892
|
+
type: string
|
|
2893
|
+
format: date-time
|
|
2894
|
+
last_used_at:
|
|
2895
|
+
type: string
|
|
2896
|
+
format: date-time
|
|
2897
|
+
expires_at:
|
|
2898
|
+
type: string
|
|
2899
|
+
format: date-time
|
|
2900
|
+
|
|
2901
|
+
AccountTokenCreated:
|
|
2902
|
+
allOf:
|
|
2903
|
+
- $ref: "#/components/schemas/AccountTokenView"
|
|
2904
|
+
- type: object
|
|
2905
|
+
required: [raw_key]
|
|
2906
|
+
properties:
|
|
2907
|
+
raw_key:
|
|
2908
|
+
type: string
|
|
2909
|
+
description: The unhashed PAT. Surfaced ONCE at creation; the server keeps only HMAC(raw_key).
|
|
2910
|
+
|
|
2911
|
+
CustomDomainCreateRequest:
|
|
2912
|
+
type: object
|
|
2913
|
+
required: [hostname]
|
|
2914
|
+
properties:
|
|
2915
|
+
hostname:
|
|
2916
|
+
type: string
|
|
2917
|
+
|
|
2918
|
+
CustomDomain:
|
|
2919
|
+
type: object
|
|
2920
|
+
required: [hostname, project_id, verified, cert_status, created_at]
|
|
2921
|
+
properties:
|
|
2922
|
+
hostname:
|
|
2923
|
+
type: string
|
|
2924
|
+
project_id:
|
|
2925
|
+
type: string
|
|
2926
|
+
verified:
|
|
2927
|
+
type: boolean
|
|
2928
|
+
verified_at:
|
|
2929
|
+
type: string
|
|
2930
|
+
format: date-time
|
|
2931
|
+
cert_status:
|
|
2932
|
+
type: string
|
|
2933
|
+
description: Lifecycle of the issued TLS cert (e.g. pending, issued).
|
|
2934
|
+
txt_record:
|
|
2935
|
+
type: string
|
|
2936
|
+
description: Hostname to publish a TXT record under (e.g. `_mortar.example.com`).
|
|
2937
|
+
txt_value:
|
|
2938
|
+
type: string
|
|
2939
|
+
description: The opaque verification token to set as the TXT value.
|
|
2940
|
+
created_at:
|
|
2941
|
+
type: string
|
|
2942
|
+
format: date-time
|