@primitivedotdev/sdk 0.19.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,7 +22,11 @@ export const openapiDocument = {
22
22
  "servers": [
23
23
  {
24
24
  "url": "https://www.primitive.dev/api/v1",
25
- "description": "Production"
25
+ "description": "Primary API host (PRIMITIVE_API_BASE_URL_1). Carries every operation\nexcept attachment-supporting send. Vercel-backed; request body is\ncapped at 4.5 MB by the platform.\n"
26
+ },
27
+ {
28
+ "url": "https://api.primitive.dev/v1",
29
+ "description": "Attachments-supporting send host (PRIMITIVE_API_BASE_URL_2).\nCloudflare Worker with a ~30 MiB raw request body cap (before\nbase64 encoding). Today only `/send-mail` is hosted here; future\nlarge-body operations will migrate here over time. SDK clients\nroute /send-mail to this server automatically.\n"
26
30
  }
27
31
  ],
28
32
  "security": [
@@ -62,6 +66,10 @@ export const openapiDocument = {
62
66
  {
63
67
  "name": "Webhook Deliveries",
64
68
  "description": "View and replay webhook delivery attempts"
69
+ },
70
+ {
71
+ "name": "Functions",
72
+ "description": "Deploy JavaScript handlers that run on inbound mail. Each function\nexports a default async handler receiving the `email.received`\nevent. Code runs on Primitive's edge runtime; there is no\ninfrastructure to manage. Secrets land in `env` as encrypted\nbindings and are refreshed on every redeploy.\n"
65
73
  }
66
74
  ],
67
75
  "paths": {
@@ -873,6 +881,230 @@ export const openapiDocument = {
873
881
  }
874
882
  }
875
883
  },
884
+ "/emails/search": {
885
+ "get": {
886
+ "operationId": "searchEmails",
887
+ "summary": "Search inbound emails",
888
+ "description": "Searches inbound emails with structured filters and optional\nfull-text matching across parsed email fields. This endpoint is\noptimized for filtered inbox views and CLI polling workflows:\ncallers that only need new accepted mail can pass\n`sort=received_at_asc`, `snippet=false`, `include_facets=false`,\nand a `date_from` timestamp.\n\n`q`, `subject`, and `body` use the same English full-text index\nas the web inbox search. Structured filters such as `from`, `to`,\n`domain_id`, status, attachment presence, and spam score bounds\nare combined with the text query.\n",
889
+ "tags": [
890
+ "Emails"
891
+ ],
892
+ "parameters": [
893
+ {
894
+ "name": "q",
895
+ "in": "query",
896
+ "schema": {
897
+ "type": "string",
898
+ "maxLength": 500
899
+ },
900
+ "description": "Full-text search DSL query."
901
+ },
902
+ {
903
+ "name": "from",
904
+ "in": "query",
905
+ "schema": {
906
+ "type": "string",
907
+ "maxLength": 255
908
+ },
909
+ "description": "Filter by sender address or sender domain."
910
+ },
911
+ {
912
+ "name": "to",
913
+ "in": "query",
914
+ "schema": {
915
+ "type": "string",
916
+ "maxLength": 255
917
+ },
918
+ "description": "Filter by recipient address or recipient domain."
919
+ },
920
+ {
921
+ "name": "subject",
922
+ "in": "query",
923
+ "schema": {
924
+ "type": "string",
925
+ "maxLength": 500
926
+ },
927
+ "description": "Full-text search restricted to the subject field."
928
+ },
929
+ {
930
+ "name": "body",
931
+ "in": "query",
932
+ "schema": {
933
+ "type": "string",
934
+ "maxLength": 2000
935
+ },
936
+ "description": "Full-text search restricted to the parsed text body."
937
+ },
938
+ {
939
+ "name": "domain_id",
940
+ "in": "query",
941
+ "schema": {
942
+ "type": "string",
943
+ "format": "uuid"
944
+ },
945
+ "description": "Filter by domain ID."
946
+ },
947
+ {
948
+ "name": "status",
949
+ "in": "query",
950
+ "schema": {
951
+ "$ref": "#/components/schemas/EmailStatus"
952
+ },
953
+ "description": "Filter by inbound email lifecycle status."
954
+ },
955
+ {
956
+ "name": "date_from",
957
+ "in": "query",
958
+ "schema": {
959
+ "type": "string",
960
+ "format": "date-time"
961
+ },
962
+ "description": "Filter emails received on or after this timestamp."
963
+ },
964
+ {
965
+ "name": "date_to",
966
+ "in": "query",
967
+ "schema": {
968
+ "type": "string",
969
+ "format": "date-time"
970
+ },
971
+ "description": "Filter emails received on or before this timestamp."
972
+ },
973
+ {
974
+ "name": "has_attachment",
975
+ "in": "query",
976
+ "schema": {
977
+ "type": "string",
978
+ "enum": [
979
+ "true",
980
+ "false"
981
+ ]
982
+ },
983
+ "description": "Filter by whether the email has one or more attachments."
984
+ },
985
+ {
986
+ "name": "spam_score_lt",
987
+ "in": "query",
988
+ "schema": {
989
+ "type": "number"
990
+ },
991
+ "description": "Filter to emails with spam score below this value."
992
+ },
993
+ {
994
+ "name": "spam_score_gte",
995
+ "in": "query",
996
+ "schema": {
997
+ "type": "number"
998
+ },
999
+ "description": "Filter to emails with spam score greater than or equal to this value."
1000
+ },
1001
+ {
1002
+ "name": "sort",
1003
+ "in": "query",
1004
+ "schema": {
1005
+ "type": "string",
1006
+ "enum": [
1007
+ "relevance",
1008
+ "received_at_desc",
1009
+ "received_at_asc"
1010
+ ]
1011
+ },
1012
+ "description": "Sort mode. Defaults to relevance when a text query is present,\notherwise `received_at_desc`.\n"
1013
+ },
1014
+ {
1015
+ "name": "cursor",
1016
+ "in": "query",
1017
+ "schema": {
1018
+ "type": "string",
1019
+ "maxLength": 200
1020
+ },
1021
+ "description": "Opaque pagination cursor from a previous search response."
1022
+ },
1023
+ {
1024
+ "$ref": "#/components/parameters/Limit"
1025
+ },
1026
+ {
1027
+ "name": "snippet",
1028
+ "in": "query",
1029
+ "schema": {
1030
+ "type": "string",
1031
+ "enum": [
1032
+ "true",
1033
+ "false"
1034
+ ],
1035
+ "default": "true"
1036
+ },
1037
+ "description": "Include subject/body highlight snippets when text search is active."
1038
+ },
1039
+ {
1040
+ "name": "include_facets",
1041
+ "in": "query",
1042
+ "schema": {
1043
+ "type": "string",
1044
+ "enum": [
1045
+ "true",
1046
+ "false"
1047
+ ],
1048
+ "default": "true"
1049
+ },
1050
+ "description": "Include facet counts for sender, domain, status, and attachment presence."
1051
+ }
1052
+ ],
1053
+ "responses": {
1054
+ "200": {
1055
+ "description": "Search results",
1056
+ "content": {
1057
+ "application/json": {
1058
+ "schema": {
1059
+ "allOf": [
1060
+ {
1061
+ "$ref": "#/components/schemas/SuccessEnvelope"
1062
+ },
1063
+ {
1064
+ "type": "object",
1065
+ "properties": {
1066
+ "data": {
1067
+ "type": "array",
1068
+ "items": {
1069
+ "$ref": "#/components/schemas/EmailSearchResult"
1070
+ }
1071
+ },
1072
+ "meta": {
1073
+ "$ref": "#/components/schemas/EmailSearchMeta"
1074
+ },
1075
+ "facets": {
1076
+ "$ref": "#/components/schemas/EmailSearchFacets"
1077
+ }
1078
+ },
1079
+ "required": [
1080
+ "data",
1081
+ "meta"
1082
+ ]
1083
+ }
1084
+ ]
1085
+ }
1086
+ }
1087
+ }
1088
+ },
1089
+ "400": {
1090
+ "$ref": "#/components/responses/ValidationError"
1091
+ },
1092
+ "401": {
1093
+ "$ref": "#/components/responses/Unauthorized"
1094
+ },
1095
+ "504": {
1096
+ "description": "Search query timed out",
1097
+ "content": {
1098
+ "application/json": {
1099
+ "schema": {
1100
+ "$ref": "#/components/schemas/ErrorResponse"
1101
+ }
1102
+ }
1103
+ }
1104
+ }
1105
+ }
1106
+ }
1107
+ },
876
1108
  "/emails/{id}": {
877
1109
  "parameters": [
878
1110
  {
@@ -1877,7 +2109,17 @@ export const openapiDocument = {
1877
2109
  "post": {
1878
2110
  "operationId": "sendEmail",
1879
2111
  "summary": "Send outbound email",
1880
- "description": "Sends an outbound email through Primitive's outbound relay. By default\nthe request returns once the relay accepts the message for delivery.\nSet `wait: true` to wait for the first downstream SMTP delivery outcome.\n",
2112
+ "description": "Sends an outbound email through Primitive's outbound relay. By default\nthe request returns once the relay accepts the message for delivery.\nSet `wait: true` to wait for the first downstream SMTP delivery outcome.\n\n**Host routing.** /send-mail is served by the attachments-\nsupporting host (`https://api.primitive.dev/v1`) so the\nrequest body can carry inline attachments up to ~30 MiB raw.\nThe primary host (`https://www.primitive.dev/api/v1`) also\naccepts /send-mail for attachment-free sends; sends WITH\nattachments to the primary host return 413\n`attachments_unsupported_on_this_endpoint`. The typed SDKs\nroute /send-mail to the attachments host automatically.\n",
2113
+ "servers": [
2114
+ {
2115
+ "url": "https://api.primitive.dev/v1",
2116
+ "description": "Attachments-supporting send host (recommended)"
2117
+ },
2118
+ {
2119
+ "url": "https://www.primitive.dev/api/v1",
2120
+ "description": "Primary host (attachment-free sends only)"
2121
+ }
2122
+ ],
1881
2123
  "tags": [
1882
2124
  "Sending"
1883
2125
  ],
@@ -2095,46 +2337,580 @@ export const openapiDocument = {
2095
2337
  }
2096
2338
  }
2097
2339
  }
2098
- }
2099
- },
2100
- "components": {
2101
- "securitySchemes": {
2102
- "BearerAuth": {
2103
- "type": "http",
2104
- "scheme": "bearer",
2105
- "description": "API key with `prim_` prefix: `Authorization: Bearer prim_<key>`"
2106
- },
2107
- "DownloadToken": {
2108
- "type": "apiKey",
2109
- "in": "query",
2110
- "name": "token",
2111
- "description": "Signed download token provided in webhook payloads"
2112
- }
2113
2340
  },
2114
- "parameters": {
2115
- "ResourceId": {
2116
- "name": "id",
2117
- "in": "path",
2118
- "required": true,
2119
- "schema": {
2120
- "type": "string",
2121
- "format": "uuid"
2122
- },
2123
- "description": "Resource UUID"
2341
+ "/functions": {
2342
+ "get": {
2343
+ "operationId": "listFunctions",
2344
+ "summary": "List functions",
2345
+ "description": "Returns every active (non-deleted) function in the org, newest\nfirst. Each entry carries the deploy status and the gateway URL\nthat the platform's webhook delivery loop posts to. To inspect\nthe source code or deploy errors, use `GET /functions/{id}`.\n",
2346
+ "tags": [
2347
+ "Functions"
2348
+ ],
2349
+ "responses": {
2350
+ "200": {
2351
+ "description": "List of functions",
2352
+ "content": {
2353
+ "application/json": {
2354
+ "schema": {
2355
+ "allOf": [
2356
+ {
2357
+ "$ref": "#/components/schemas/SuccessEnvelope"
2358
+ },
2359
+ {
2360
+ "type": "object",
2361
+ "properties": {
2362
+ "data": {
2363
+ "type": "array",
2364
+ "items": {
2365
+ "$ref": "#/components/schemas/FunctionListItem"
2366
+ }
2367
+ }
2368
+ }
2369
+ }
2370
+ ]
2371
+ }
2372
+ }
2373
+ }
2374
+ },
2375
+ "401": {
2376
+ "$ref": "#/components/responses/Unauthorized"
2377
+ }
2378
+ }
2124
2379
  },
2125
- "Cursor": {
2126
- "name": "cursor",
2127
- "in": "query",
2128
- "schema": {
2129
- "type": "string"
2380
+ "post": {
2381
+ "operationId": "createFunction",
2382
+ "summary": "Deploy a function",
2383
+ "description": "Creates and deploys a new function. The handler must be a single\nESM module that exports a default async function receiving the\n`email.received` event (see the Webhook payload section for the\nfull schema). Code is bundled before being uploaded; ship a\nsingle self-contained file rather than relying on external\nimports.\n\n**Code limits.** `code` is capped at 1 MiB UTF-8. `sourceMap`\n(optional) is capped at 5 MiB UTF-8 and is stored only on the\nedge runtime side; it is not persisted in Primitive's database.\n\n**Auto-wiring.** On successful deploy, Primitive automatically\ncreates a webhook endpoint that delivers inbound mail to the\nfunction. There is nothing to configure on the Endpoints API\nfor this to work; the gateway URL returned here is for\nreference only and is not directly callable from outside.\n\n**Secrets.** New functions ship with the managed secrets\n(`PRIMITIVE_WEBHOOK_SECRET`, `PRIMITIVE_API_KEY`) already\nbound. Add user-set secrets via\n`POST /functions/{id}/secrets`; secret writes only land in the\nrunning handler on the next redeploy.\n",
2384
+ "tags": [
2385
+ "Functions"
2386
+ ],
2387
+ "requestBody": {
2388
+ "required": true,
2389
+ "content": {
2390
+ "application/json": {
2391
+ "schema": {
2392
+ "$ref": "#/components/schemas/CreateFunctionInput"
2393
+ }
2394
+ }
2395
+ }
2130
2396
  },
2131
- "description": "Pagination cursor from a previous response's `meta.cursor` field.\nFormat: `{ISO-datetime}|{id}`\n"
2132
- },
2133
- "Limit": {
2134
- "name": "limit",
2135
- "in": "query",
2136
- "schema": {
2137
- "type": "integer",
2397
+ "responses": {
2398
+ "201": {
2399
+ "description": "Function created and deployed",
2400
+ "content": {
2401
+ "application/json": {
2402
+ "schema": {
2403
+ "allOf": [
2404
+ {
2405
+ "$ref": "#/components/schemas/SuccessEnvelope"
2406
+ },
2407
+ {
2408
+ "type": "object",
2409
+ "properties": {
2410
+ "data": {
2411
+ "$ref": "#/components/schemas/CreateFunctionResult"
2412
+ }
2413
+ }
2414
+ }
2415
+ ]
2416
+ }
2417
+ }
2418
+ }
2419
+ },
2420
+ "400": {
2421
+ "$ref": "#/components/responses/ValidationError"
2422
+ },
2423
+ "401": {
2424
+ "$ref": "#/components/responses/Unauthorized"
2425
+ },
2426
+ "409": {
2427
+ "description": "A function with this name already exists in the org",
2428
+ "content": {
2429
+ "application/json": {
2430
+ "schema": {
2431
+ "$ref": "#/components/schemas/ErrorResponse"
2432
+ }
2433
+ }
2434
+ }
2435
+ },
2436
+ "502": {
2437
+ "$ref": "#/components/responses/BadGateway"
2438
+ }
2439
+ }
2440
+ }
2441
+ },
2442
+ "/functions/{id}": {
2443
+ "parameters": [
2444
+ {
2445
+ "$ref": "#/components/parameters/ResourceId"
2446
+ }
2447
+ ],
2448
+ "get": {
2449
+ "operationId": "getFunction",
2450
+ "summary": "Get a function",
2451
+ "description": "Returns the full record for a function, including its current\nsource code and the deploy status / error from the most recent\ndeploy attempt.\n",
2452
+ "tags": [
2453
+ "Functions"
2454
+ ],
2455
+ "responses": {
2456
+ "200": {
2457
+ "description": "Function record",
2458
+ "content": {
2459
+ "application/json": {
2460
+ "schema": {
2461
+ "allOf": [
2462
+ {
2463
+ "$ref": "#/components/schemas/SuccessEnvelope"
2464
+ },
2465
+ {
2466
+ "type": "object",
2467
+ "properties": {
2468
+ "data": {
2469
+ "$ref": "#/components/schemas/FunctionDetail"
2470
+ }
2471
+ }
2472
+ }
2473
+ ]
2474
+ }
2475
+ }
2476
+ }
2477
+ },
2478
+ "401": {
2479
+ "$ref": "#/components/responses/Unauthorized"
2480
+ },
2481
+ "404": {
2482
+ "$ref": "#/components/responses/NotFound"
2483
+ }
2484
+ }
2485
+ },
2486
+ "put": {
2487
+ "operationId": "updateFunction",
2488
+ "summary": "Update and redeploy a function",
2489
+ "description": "Replaces the function's source code with the body's `code` and\ntriggers a redeploy. Same size limits as `POST /functions`.\nUse this verb to push secret writes into the running handler:\npassing the same `code` re-runs the deploy and refreshes the\nbinding set with the latest values from the secrets table.\n\nOn a 502 deploy failure, the previously-deployed code stays\nlive; the runtime never serves a half-built bundle. The\n`deploy_error` field on the returned record carries the error\nthat came back from the runtime so you can surface it to users\nwithout polling.\n",
2490
+ "tags": [
2491
+ "Functions"
2492
+ ],
2493
+ "requestBody": {
2494
+ "required": true,
2495
+ "content": {
2496
+ "application/json": {
2497
+ "schema": {
2498
+ "$ref": "#/components/schemas/UpdateFunctionInput"
2499
+ }
2500
+ }
2501
+ }
2502
+ },
2503
+ "responses": {
2504
+ "200": {
2505
+ "description": "Updated function",
2506
+ "content": {
2507
+ "application/json": {
2508
+ "schema": {
2509
+ "allOf": [
2510
+ {
2511
+ "$ref": "#/components/schemas/SuccessEnvelope"
2512
+ },
2513
+ {
2514
+ "type": "object",
2515
+ "properties": {
2516
+ "data": {
2517
+ "$ref": "#/components/schemas/FunctionDetail"
2518
+ }
2519
+ }
2520
+ }
2521
+ ]
2522
+ }
2523
+ }
2524
+ }
2525
+ },
2526
+ "400": {
2527
+ "$ref": "#/components/responses/ValidationError"
2528
+ },
2529
+ "401": {
2530
+ "$ref": "#/components/responses/Unauthorized"
2531
+ },
2532
+ "404": {
2533
+ "$ref": "#/components/responses/NotFound"
2534
+ },
2535
+ "502": {
2536
+ "$ref": "#/components/responses/BadGateway"
2537
+ }
2538
+ }
2539
+ },
2540
+ "delete": {
2541
+ "operationId": "deleteFunction",
2542
+ "summary": "Delete a function",
2543
+ "description": "Soft-deletes the function row, removes the script from the edge\nruntime, and deactivates the auto-wired webhook endpoint so no\nfurther inbound mail is delivered. Past deploy history,\ninvocations, and logs are retained.\n\nReturns 502 if the runtime delete fails partway; the function\nrow stays in place and the call is safe to retry until it\nsucceeds.\n",
2544
+ "tags": [
2545
+ "Functions"
2546
+ ],
2547
+ "responses": {
2548
+ "200": {
2549
+ "$ref": "#/components/responses/Deleted"
2550
+ },
2551
+ "401": {
2552
+ "$ref": "#/components/responses/Unauthorized"
2553
+ },
2554
+ "404": {
2555
+ "$ref": "#/components/responses/NotFound"
2556
+ },
2557
+ "502": {
2558
+ "$ref": "#/components/responses/BadGateway"
2559
+ }
2560
+ }
2561
+ }
2562
+ },
2563
+ "/functions/{id}/test": {
2564
+ "parameters": [
2565
+ {
2566
+ "$ref": "#/components/parameters/ResourceId"
2567
+ }
2568
+ ],
2569
+ "post": {
2570
+ "operationId": "testFunction",
2571
+ "summary": "Send a test invocation",
2572
+ "description": "Sends a real test email from a Primitive-controlled sender to a\nsynthetic local-part on one of the org's verified inbound\ndomains. The function fires through the normal MX delivery\npath, so reply / send-mail calls from inside the handler\nagainst the inbound's `email.id` work the same as in\nproduction. Returns immediately after the send is queued; the\ninvocation appears on the function's invocations list within a\nfew seconds.\n\nRequires that the function is currently `deployed`. Returns 422\nif the function is in `pending` or `failed` state, or if the\norg has no verified inbound domain to receive the test mail.\n",
2573
+ "tags": [
2574
+ "Functions"
2575
+ ],
2576
+ "responses": {
2577
+ "200": {
2578
+ "description": "Test send queued",
2579
+ "content": {
2580
+ "application/json": {
2581
+ "schema": {
2582
+ "allOf": [
2583
+ {
2584
+ "$ref": "#/components/schemas/SuccessEnvelope"
2585
+ },
2586
+ {
2587
+ "type": "object",
2588
+ "properties": {
2589
+ "data": {
2590
+ "$ref": "#/components/schemas/TestInvocationResult"
2591
+ }
2592
+ }
2593
+ }
2594
+ ]
2595
+ }
2596
+ }
2597
+ }
2598
+ },
2599
+ "400": {
2600
+ "$ref": "#/components/responses/ValidationError"
2601
+ },
2602
+ "401": {
2603
+ "$ref": "#/components/responses/Unauthorized"
2604
+ },
2605
+ "404": {
2606
+ "$ref": "#/components/responses/NotFound"
2607
+ },
2608
+ "422": {
2609
+ "description": "Function not in a state that can be invoked, or no inbound domain configured",
2610
+ "content": {
2611
+ "application/json": {
2612
+ "schema": {
2613
+ "$ref": "#/components/schemas/ErrorResponse"
2614
+ }
2615
+ }
2616
+ }
2617
+ },
2618
+ "502": {
2619
+ "$ref": "#/components/responses/BadGateway"
2620
+ },
2621
+ "503": {
2622
+ "description": "Sending agent misconfigured",
2623
+ "content": {
2624
+ "application/json": {
2625
+ "schema": {
2626
+ "$ref": "#/components/schemas/ErrorResponse"
2627
+ }
2628
+ }
2629
+ }
2630
+ }
2631
+ }
2632
+ }
2633
+ },
2634
+ "/functions/{id}/secrets": {
2635
+ "parameters": [
2636
+ {
2637
+ "$ref": "#/components/parameters/ResourceId"
2638
+ }
2639
+ ],
2640
+ "get": {
2641
+ "operationId": "listFunctionSecrets",
2642
+ "summary": "List a function's secrets",
2643
+ "description": "Returns metadata for every secret bound to the function, with\nmanaged entries (provisioned by Primitive) listed first and\nuser-set entries listed alphabetically after. **Values are\nnever returned.** Secret writes are write-only.\n\nManaged entries (e.g. `PRIMITIVE_WEBHOOK_SECRET`,\n`PRIMITIVE_API_KEY`) carry a `description` instead of\n`created_at` / `updated_at`. They cannot be created, updated,\nor deleted via this API.\n",
2644
+ "tags": [
2645
+ "Functions"
2646
+ ],
2647
+ "responses": {
2648
+ "200": {
2649
+ "description": "List of secrets (metadata only, no values)",
2650
+ "content": {
2651
+ "application/json": {
2652
+ "schema": {
2653
+ "allOf": [
2654
+ {
2655
+ "$ref": "#/components/schemas/SuccessEnvelope"
2656
+ },
2657
+ {
2658
+ "type": "object",
2659
+ "properties": {
2660
+ "data": {
2661
+ "type": "object",
2662
+ "properties": {
2663
+ "items": {
2664
+ "type": "array",
2665
+ "items": {
2666
+ "$ref": "#/components/schemas/FunctionSecretListItem"
2667
+ }
2668
+ }
2669
+ },
2670
+ "required": [
2671
+ "items"
2672
+ ]
2673
+ }
2674
+ }
2675
+ }
2676
+ ]
2677
+ }
2678
+ }
2679
+ }
2680
+ },
2681
+ "401": {
2682
+ "$ref": "#/components/responses/Unauthorized"
2683
+ },
2684
+ "404": {
2685
+ "$ref": "#/components/responses/NotFound"
2686
+ }
2687
+ }
2688
+ },
2689
+ "post": {
2690
+ "operationId": "createFunctionSecret",
2691
+ "summary": "Create or update a secret",
2692
+ "description": "Idempotent insert-or-update keyed on `(function_id, key)`.\nReturns 201 the first time the key is set, 200 on subsequent\nupdates. Values are encrypted at rest and only become visible\nto the running handler on the next deploy (`PUT /functions/{id}`\nwith the existing code is sufficient to refresh bindings).\n\nKeys must match `^[A-Z_][A-Z0-9_]*$` (uppercase letters,\ndigits, underscores; first character is a letter or\nunderscore). Values are at most 4096 UTF-8 bytes. System-\nmanaged keys are reserved and rejected.\n",
2693
+ "tags": [
2694
+ "Functions"
2695
+ ],
2696
+ "requestBody": {
2697
+ "required": true,
2698
+ "content": {
2699
+ "application/json": {
2700
+ "schema": {
2701
+ "$ref": "#/components/schemas/CreateFunctionSecretInput"
2702
+ }
2703
+ }
2704
+ }
2705
+ },
2706
+ "responses": {
2707
+ "200": {
2708
+ "description": "Secret updated",
2709
+ "content": {
2710
+ "application/json": {
2711
+ "schema": {
2712
+ "allOf": [
2713
+ {
2714
+ "$ref": "#/components/schemas/SuccessEnvelope"
2715
+ },
2716
+ {
2717
+ "type": "object",
2718
+ "properties": {
2719
+ "data": {
2720
+ "$ref": "#/components/schemas/FunctionSecretWriteResult"
2721
+ }
2722
+ }
2723
+ }
2724
+ ]
2725
+ }
2726
+ }
2727
+ }
2728
+ },
2729
+ "201": {
2730
+ "description": "Secret created",
2731
+ "content": {
2732
+ "application/json": {
2733
+ "schema": {
2734
+ "allOf": [
2735
+ {
2736
+ "$ref": "#/components/schemas/SuccessEnvelope"
2737
+ },
2738
+ {
2739
+ "type": "object",
2740
+ "properties": {
2741
+ "data": {
2742
+ "$ref": "#/components/schemas/FunctionSecretWriteResult"
2743
+ }
2744
+ }
2745
+ }
2746
+ ]
2747
+ }
2748
+ }
2749
+ }
2750
+ },
2751
+ "400": {
2752
+ "$ref": "#/components/responses/ValidationError"
2753
+ },
2754
+ "401": {
2755
+ "$ref": "#/components/responses/Unauthorized"
2756
+ },
2757
+ "404": {
2758
+ "$ref": "#/components/responses/NotFound"
2759
+ }
2760
+ }
2761
+ }
2762
+ },
2763
+ "/functions/{id}/secrets/{key}": {
2764
+ "parameters": [
2765
+ {
2766
+ "$ref": "#/components/parameters/ResourceId"
2767
+ },
2768
+ {
2769
+ "name": "key",
2770
+ "in": "path",
2771
+ "required": true,
2772
+ "description": "Secret key. Must match `^[A-Z_][A-Z0-9_]*$`.",
2773
+ "schema": {
2774
+ "type": "string",
2775
+ "pattern": "^[A-Z_][A-Z0-9_]*$"
2776
+ }
2777
+ }
2778
+ ],
2779
+ "put": {
2780
+ "operationId": "setFunctionSecret",
2781
+ "summary": "Set a secret by key",
2782
+ "description": "Path-keyed companion to `POST /functions/{id}/secrets`.\nIdempotent: returns 201 the first time the key is set, 200 on\nsubsequent updates. Same validation rules and same write-only\nguarantees as the POST verb; the new value lands in the running\nhandler on the next deploy.\n",
2783
+ "tags": [
2784
+ "Functions"
2785
+ ],
2786
+ "requestBody": {
2787
+ "required": true,
2788
+ "content": {
2789
+ "application/json": {
2790
+ "schema": {
2791
+ "$ref": "#/components/schemas/SetFunctionSecretInput"
2792
+ }
2793
+ }
2794
+ }
2795
+ },
2796
+ "responses": {
2797
+ "200": {
2798
+ "description": "Secret updated",
2799
+ "content": {
2800
+ "application/json": {
2801
+ "schema": {
2802
+ "allOf": [
2803
+ {
2804
+ "$ref": "#/components/schemas/SuccessEnvelope"
2805
+ },
2806
+ {
2807
+ "type": "object",
2808
+ "properties": {
2809
+ "data": {
2810
+ "$ref": "#/components/schemas/FunctionSecretWriteResult"
2811
+ }
2812
+ }
2813
+ }
2814
+ ]
2815
+ }
2816
+ }
2817
+ }
2818
+ },
2819
+ "201": {
2820
+ "description": "Secret created",
2821
+ "content": {
2822
+ "application/json": {
2823
+ "schema": {
2824
+ "allOf": [
2825
+ {
2826
+ "$ref": "#/components/schemas/SuccessEnvelope"
2827
+ },
2828
+ {
2829
+ "type": "object",
2830
+ "properties": {
2831
+ "data": {
2832
+ "$ref": "#/components/schemas/FunctionSecretWriteResult"
2833
+ }
2834
+ }
2835
+ }
2836
+ ]
2837
+ }
2838
+ }
2839
+ }
2840
+ },
2841
+ "400": {
2842
+ "$ref": "#/components/responses/ValidationError"
2843
+ },
2844
+ "401": {
2845
+ "$ref": "#/components/responses/Unauthorized"
2846
+ },
2847
+ "404": {
2848
+ "$ref": "#/components/responses/NotFound"
2849
+ }
2850
+ }
2851
+ },
2852
+ "delete": {
2853
+ "operationId": "deleteFunctionSecret",
2854
+ "summary": "Delete a secret",
2855
+ "description": "Removes the secret. The binding stays live in the running\nhandler until the next deploy refreshes the binding set\n(`PUT /functions/{id}` with the existing code is sufficient).\nReturns 404 if the key did not exist. Managed system keys\ncannot be deleted.\n",
2856
+ "tags": [
2857
+ "Functions"
2858
+ ],
2859
+ "responses": {
2860
+ "204": {
2861
+ "description": "Secret deleted"
2862
+ },
2863
+ "400": {
2864
+ "$ref": "#/components/responses/ValidationError"
2865
+ },
2866
+ "401": {
2867
+ "$ref": "#/components/responses/Unauthorized"
2868
+ },
2869
+ "404": {
2870
+ "$ref": "#/components/responses/NotFound"
2871
+ }
2872
+ }
2873
+ }
2874
+ }
2875
+ },
2876
+ "components": {
2877
+ "securitySchemes": {
2878
+ "BearerAuth": {
2879
+ "type": "http",
2880
+ "scheme": "bearer",
2881
+ "description": "API key with `prim_` prefix: `Authorization: Bearer prim_<key>`"
2882
+ },
2883
+ "DownloadToken": {
2884
+ "type": "apiKey",
2885
+ "in": "query",
2886
+ "name": "token",
2887
+ "description": "Signed download token provided in webhook payloads"
2888
+ }
2889
+ },
2890
+ "parameters": {
2891
+ "ResourceId": {
2892
+ "name": "id",
2893
+ "in": "path",
2894
+ "required": true,
2895
+ "schema": {
2896
+ "type": "string",
2897
+ "format": "uuid"
2898
+ },
2899
+ "description": "Resource UUID"
2900
+ },
2901
+ "Cursor": {
2902
+ "name": "cursor",
2903
+ "in": "query",
2904
+ "schema": {
2905
+ "type": "string"
2906
+ },
2907
+ "description": "Pagination cursor from a previous response's `meta.cursor` field.\nFormat: `{ISO-datetime}|{id}`\n"
2908
+ },
2909
+ "Limit": {
2910
+ "name": "limit",
2911
+ "in": "query",
2912
+ "schema": {
2913
+ "type": "integer",
2138
2914
  "minimum": 1,
2139
2915
  "maximum": 100,
2140
2916
  "default": 50
@@ -2407,6 +3183,7 @@ export const openapiDocument = {
2407
3183
  "outbound_relay_failed",
2408
3184
  "discard_not_enabled",
2409
3185
  "inbound_not_repliable",
3186
+ "search_timeout",
2410
3187
  "authorization_pending",
2411
3188
  "slow_down",
2412
3189
  "access_denied",
@@ -3091,22 +3868,178 @@ export const openapiDocument = {
3091
3868
  "null"
3092
3869
  ]
3093
3870
  },
3094
- "webhook_status": {
3095
- "$ref": "#/components/schemas/EmailWebhookStatus"
3871
+ "webhook_status": {
3872
+ "$ref": "#/components/schemas/EmailWebhookStatus"
3873
+ },
3874
+ "webhook_attempt_count": {
3875
+ "type": "integer"
3876
+ }
3877
+ },
3878
+ "required": [
3879
+ "id",
3880
+ "status",
3881
+ "sender",
3882
+ "recipient",
3883
+ "domain",
3884
+ "created_at",
3885
+ "received_at",
3886
+ "webhook_attempt_count"
3887
+ ]
3888
+ },
3889
+ "EmailSearchHighlights": {
3890
+ "type": "object",
3891
+ "properties": {
3892
+ "subject": {
3893
+ "type": "array",
3894
+ "items": {
3895
+ "type": "string"
3896
+ },
3897
+ "description": "Subject snippets with matching terms highlighted."
3898
+ },
3899
+ "body": {
3900
+ "type": "array",
3901
+ "items": {
3902
+ "type": "string"
3903
+ },
3904
+ "description": "Body snippets with matching terms highlighted."
3905
+ }
3906
+ },
3907
+ "required": [
3908
+ "subject",
3909
+ "body"
3910
+ ]
3911
+ },
3912
+ "EmailSearchResult": {
3913
+ "allOf": [
3914
+ {
3915
+ "$ref": "#/components/schemas/EmailSummary"
3916
+ },
3917
+ {
3918
+ "type": "object",
3919
+ "properties": {
3920
+ "attachment_count": {
3921
+ "type": "integer",
3922
+ "description": "Number of parsed attachments on the email."
3923
+ },
3924
+ "from_known_address": {
3925
+ "type": "boolean",
3926
+ "description": "Whether the parsed From address is known to this org from prior authenticated inbound mail."
3927
+ },
3928
+ "score": {
3929
+ "type": "number",
3930
+ "description": "Relevance score. Present only when sorting by relevance."
3931
+ },
3932
+ "highlights": {
3933
+ "$ref": "#/components/schemas/EmailSearchHighlights"
3934
+ }
3935
+ },
3936
+ "required": [
3937
+ "attachment_count",
3938
+ "from_known_address"
3939
+ ]
3940
+ }
3941
+ ]
3942
+ },
3943
+ "EmailSearchMeta": {
3944
+ "type": "object",
3945
+ "properties": {
3946
+ "total": {
3947
+ "type": "integer",
3948
+ "description": "Total number of matching records, capped when `total_capped` is true."
3949
+ },
3950
+ "total_capped": {
3951
+ "type": "boolean",
3952
+ "description": "Whether `total` was capped instead of counted exactly."
3953
+ },
3954
+ "limit": {
3955
+ "type": "integer",
3956
+ "description": "Page size used for this request."
3957
+ },
3958
+ "cursor": {
3959
+ "type": [
3960
+ "string",
3961
+ "null"
3962
+ ],
3963
+ "description": "Cursor for the next search page, or null if no more results."
3964
+ },
3965
+ "sort": {
3966
+ "type": "string",
3967
+ "enum": [
3968
+ "relevance",
3969
+ "received_at_desc",
3970
+ "received_at_asc"
3971
+ ],
3972
+ "description": "Sort mode used for the result page."
3973
+ }
3974
+ },
3975
+ "required": [
3976
+ "total",
3977
+ "total_capped",
3978
+ "limit",
3979
+ "cursor",
3980
+ "sort"
3981
+ ]
3982
+ },
3983
+ "EmailSearchFacetBucket": {
3984
+ "type": "object",
3985
+ "properties": {
3986
+ "value": {
3987
+ "type": [
3988
+ "string",
3989
+ "null"
3990
+ ]
3991
+ },
3992
+ "count": {
3993
+ "type": "integer"
3994
+ }
3995
+ },
3996
+ "required": [
3997
+ "value",
3998
+ "count"
3999
+ ]
4000
+ },
4001
+ "EmailSearchFacets": {
4002
+ "type": "object",
4003
+ "properties": {
4004
+ "by_sender": {
4005
+ "type": "array",
4006
+ "items": {
4007
+ "$ref": "#/components/schemas/EmailSearchFacetBucket"
4008
+ }
4009
+ },
4010
+ "by_domain": {
4011
+ "type": "array",
4012
+ "items": {
4013
+ "$ref": "#/components/schemas/EmailSearchFacetBucket"
4014
+ }
3096
4015
  },
3097
- "webhook_attempt_count": {
3098
- "type": "integer"
4016
+ "by_status": {
4017
+ "type": "array",
4018
+ "items": {
4019
+ "$ref": "#/components/schemas/EmailSearchFacetBucket"
4020
+ }
4021
+ },
4022
+ "has_attachment": {
4023
+ "type": "object",
4024
+ "properties": {
4025
+ "true": {
4026
+ "type": "integer"
4027
+ },
4028
+ "false": {
4029
+ "type": "integer"
4030
+ }
4031
+ },
4032
+ "required": [
4033
+ "true",
4034
+ "false"
4035
+ ]
3099
4036
  }
3100
4037
  },
3101
4038
  "required": [
3102
- "id",
3103
- "status",
3104
- "sender",
3105
- "recipient",
3106
- "domain",
3107
- "created_at",
3108
- "received_at",
3109
- "webhook_attempt_count"
4039
+ "by_sender",
4040
+ "by_domain",
4041
+ "by_status",
4042
+ "has_attachment"
3110
4043
  ]
3111
4044
  },
3112
4045
  "EmailDetail": {
@@ -4318,6 +5251,339 @@ export const openapiDocument = {
4318
5251
  "discarded",
4319
5252
  "already_discarded"
4320
5253
  ]
5254
+ },
5255
+ "FunctionDeployStatus": {
5256
+ "type": "string",
5257
+ "enum": [
5258
+ "pending",
5259
+ "deployed",
5260
+ "failed"
5261
+ ],
5262
+ "description": "Lifecycle state of the latest deploy attempt:\n * `pending` — deploy in flight; the runtime has not yet\n confirmed the new bundle is live.\n * `deployed` — the running edge handler is the latest code.\n * `failed` — the most recent deploy attempt failed; the\n previously-live code (if any) is still running. The\n `deploy_error` field carries the error message.\n"
5263
+ },
5264
+ "FunctionListItem": {
5265
+ "type": "object",
5266
+ "description": "One row from the function listing.",
5267
+ "properties": {
5268
+ "id": {
5269
+ "type": "string",
5270
+ "format": "uuid",
5271
+ "description": "Function id, also the script name in the edge runtime."
5272
+ },
5273
+ "name": {
5274
+ "type": "string",
5275
+ "description": "Slug-style name set on creation. Stable; cannot be changed."
5276
+ },
5277
+ "deploy_status": {
5278
+ "$ref": "#/components/schemas/FunctionDeployStatus"
5279
+ },
5280
+ "deployed_at": {
5281
+ "type": [
5282
+ "string",
5283
+ "null"
5284
+ ],
5285
+ "format": "date-time",
5286
+ "description": "Timestamp of the most recent successful deploy. Null until the first deploy succeeds."
5287
+ },
5288
+ "gateway_url": {
5289
+ "type": "string",
5290
+ "format": "uri",
5291
+ "description": "URL the platform's webhook delivery loop posts to in order\nto invoke the function. Reference only; not directly\ncallable from outside.\n"
5292
+ },
5293
+ "created_at": {
5294
+ "type": "string",
5295
+ "format": "date-time"
5296
+ },
5297
+ "updated_at": {
5298
+ "type": "string",
5299
+ "format": "date-time"
5300
+ }
5301
+ },
5302
+ "required": [
5303
+ "id",
5304
+ "name",
5305
+ "deploy_status",
5306
+ "gateway_url",
5307
+ "created_at",
5308
+ "updated_at"
5309
+ ]
5310
+ },
5311
+ "FunctionDetail": {
5312
+ "type": "object",
5313
+ "description": "Full function record returned by GET / PUT.",
5314
+ "properties": {
5315
+ "id": {
5316
+ "type": "string",
5317
+ "format": "uuid"
5318
+ },
5319
+ "name": {
5320
+ "type": "string"
5321
+ },
5322
+ "code": {
5323
+ "type": "string",
5324
+ "description": "The bundled handler source. UTF-8 string up to 1 MiB. The\nsame value most recently passed as `code` to POST or PUT.\n"
5325
+ },
5326
+ "deploy_status": {
5327
+ "$ref": "#/components/schemas/FunctionDeployStatus"
5328
+ },
5329
+ "deploy_error": {
5330
+ "type": [
5331
+ "string",
5332
+ "null"
5333
+ ],
5334
+ "description": "Error message from the most recent failed deploy, or null\nafter a successful deploy. Surface this to users to explain\na `failed` status without polling.\n"
5335
+ },
5336
+ "deployed_at": {
5337
+ "type": [
5338
+ "string",
5339
+ "null"
5340
+ ],
5341
+ "format": "date-time"
5342
+ },
5343
+ "gateway_url": {
5344
+ "type": "string",
5345
+ "format": "uri"
5346
+ },
5347
+ "created_at": {
5348
+ "type": "string",
5349
+ "format": "date-time"
5350
+ },
5351
+ "updated_at": {
5352
+ "type": "string",
5353
+ "format": "date-time"
5354
+ }
5355
+ },
5356
+ "required": [
5357
+ "id",
5358
+ "name",
5359
+ "code",
5360
+ "deploy_status",
5361
+ "gateway_url",
5362
+ "created_at",
5363
+ "updated_at"
5364
+ ]
5365
+ },
5366
+ "CreateFunctionInput": {
5367
+ "type": "object",
5368
+ "additionalProperties": false,
5369
+ "properties": {
5370
+ "name": {
5371
+ "type": "string",
5372
+ "pattern": "^[a-z0-9_-]{1,64}$",
5373
+ "description": "Slug-style name. Lowercase letters, digits, hyphens, and\nunderscores. 1 to 64 characters. Must be unique within the\norg; a 409 is returned on collision.\n"
5374
+ },
5375
+ "code": {
5376
+ "type": "string",
5377
+ "minLength": 1,
5378
+ "maxLength": 1048576,
5379
+ "description": "Bundled handler as a single ESM module. Up to 1 MiB UTF-8.\nMust export a default `{ async fetch(req, env, ctx) { ... } }`\nobject.\n"
5380
+ },
5381
+ "sourceMap": {
5382
+ "type": "string",
5383
+ "minLength": 1,
5384
+ "maxLength": 5242880,
5385
+ "description": "Optional source map for the bundle. Up to 5 MiB UTF-8.\nStored only on the runtime side (not in Primitive's\ndatabase) and used to symbolicate stack traces in the\nfunction's logs.\n"
5386
+ }
5387
+ },
5388
+ "required": [
5389
+ "name",
5390
+ "code"
5391
+ ]
5392
+ },
5393
+ "CreateFunctionResult": {
5394
+ "type": "object",
5395
+ "description": "Returned by POST /functions on a successful deploy.",
5396
+ "properties": {
5397
+ "id": {
5398
+ "type": "string",
5399
+ "format": "uuid"
5400
+ },
5401
+ "name": {
5402
+ "type": "string"
5403
+ },
5404
+ "deploy_status": {
5405
+ "$ref": "#/components/schemas/FunctionDeployStatus"
5406
+ },
5407
+ "gateway_url": {
5408
+ "type": "string",
5409
+ "format": "uri"
5410
+ }
5411
+ },
5412
+ "required": [
5413
+ "id",
5414
+ "name",
5415
+ "deploy_status",
5416
+ "gateway_url"
5417
+ ]
5418
+ },
5419
+ "UpdateFunctionInput": {
5420
+ "type": "object",
5421
+ "additionalProperties": false,
5422
+ "properties": {
5423
+ "code": {
5424
+ "type": "string",
5425
+ "minLength": 1,
5426
+ "maxLength": 1048576,
5427
+ "description": "New bundled handler. Same rules as CreateFunctionInput.code."
5428
+ },
5429
+ "sourceMap": {
5430
+ "type": "string",
5431
+ "minLength": 1,
5432
+ "maxLength": 5242880
5433
+ }
5434
+ },
5435
+ "required": [
5436
+ "code"
5437
+ ]
5438
+ },
5439
+ "TestInvocationResult": {
5440
+ "type": "object",
5441
+ "description": "Metadata returned by POST /functions/{id}/test. The send is\nqueued; the actual invocation lands on the function's\ninvocations list a few seconds later as the inbound mail\ntraverses the MX path.\n",
5442
+ "properties": {
5443
+ "inbound_domain": {
5444
+ "type": "string",
5445
+ "description": "Verified inbound domain the test email was sent to."
5446
+ },
5447
+ "to": {
5448
+ "type": "string",
5449
+ "description": "Synthetic local-part plus inbound_domain. Visible in the org's inbox."
5450
+ },
5451
+ "from": {
5452
+ "type": "string",
5453
+ "description": "Primitive-controlled outbound sender used for the test."
5454
+ },
5455
+ "send_id": {
5456
+ "type": "string",
5457
+ "description": "Outbound message id from the underlying send. NOT the\ninbound email's id; the inbound id is created when the\nemail arrives via MX and lands on the function's\ninvocations list.\n"
5458
+ },
5459
+ "subject": {
5460
+ "type": "string",
5461
+ "description": "Subject placed on the test email so it can be located in the inbox."
5462
+ },
5463
+ "poll_since": {
5464
+ "type": "string",
5465
+ "format": "date-time",
5466
+ "description": "ISO timestamp suitable as a `since` lower bound when\npolling /emails for the inbound's arrival. Captured\nslightly before the send to absorb light clock skew.\n"
5467
+ },
5468
+ "watch_url": {
5469
+ "type": "string",
5470
+ "format": "uri",
5471
+ "description": "Function detail page where invocations show up live."
5472
+ }
5473
+ },
5474
+ "required": [
5475
+ "inbound_domain",
5476
+ "to",
5477
+ "from",
5478
+ "send_id",
5479
+ "subject",
5480
+ "poll_since",
5481
+ "watch_url"
5482
+ ]
5483
+ },
5484
+ "FunctionSecretListItem": {
5485
+ "type": "object",
5486
+ "description": "One row from GET /functions/{id}/secrets. Discriminate on the\n`managed` field:\n * `managed = true` — system secret provisioned by Primitive.\n `description` is set; `created_at` / `updated_at` are\n null because the row is virtual (resolved at deploy time\n from the managed registry, not stored in the secrets\n table).\n * `managed = false` — secret the user set via the API.\n `created_at` / `updated_at` are set; `description` is\n null.\n",
5487
+ "properties": {
5488
+ "key": {
5489
+ "type": "string"
5490
+ },
5491
+ "managed": {
5492
+ "type": "boolean",
5493
+ "description": "True for managed system secrets, false for user-set entries."
5494
+ },
5495
+ "description": {
5496
+ "type": [
5497
+ "string",
5498
+ "null"
5499
+ ],
5500
+ "description": "Set on managed entries only; null on user-set entries."
5501
+ },
5502
+ "created_at": {
5503
+ "type": [
5504
+ "string",
5505
+ "null"
5506
+ ],
5507
+ "format": "date-time",
5508
+ "description": "Set on user-set entries only; null on managed entries."
5509
+ },
5510
+ "updated_at": {
5511
+ "type": [
5512
+ "string",
5513
+ "null"
5514
+ ],
5515
+ "format": "date-time",
5516
+ "description": "Set on user-set entries only; null on managed entries."
5517
+ }
5518
+ },
5519
+ "required": [
5520
+ "key",
5521
+ "managed"
5522
+ ]
5523
+ },
5524
+ "CreateFunctionSecretInput": {
5525
+ "type": "object",
5526
+ "additionalProperties": false,
5527
+ "description": "Body for POST /functions/{id}/secrets.",
5528
+ "properties": {
5529
+ "key": {
5530
+ "type": "string",
5531
+ "pattern": "^[A-Z_][A-Z0-9_]*$",
5532
+ "description": "Uppercase letters, digits, and underscores. Must start with\na letter or underscore. System-managed keys (e.g.\nPRIMITIVE_WEBHOOK_SECRET) are reserved.\n"
5533
+ },
5534
+ "value": {
5535
+ "type": "string",
5536
+ "minLength": 1,
5537
+ "maxLength": 4096,
5538
+ "description": "Secret value, up to 4096 UTF-8 bytes. Encrypted at rest.\nNever returned by any read endpoint.\n"
5539
+ }
5540
+ },
5541
+ "required": [
5542
+ "key",
5543
+ "value"
5544
+ ]
5545
+ },
5546
+ "SetFunctionSecretInput": {
5547
+ "type": "object",
5548
+ "additionalProperties": false,
5549
+ "description": "Body for PUT /functions/{id}/secrets/{key}. Key comes from the path.",
5550
+ "properties": {
5551
+ "value": {
5552
+ "type": "string",
5553
+ "minLength": 1,
5554
+ "maxLength": 4096
5555
+ }
5556
+ },
5557
+ "required": [
5558
+ "value"
5559
+ ]
5560
+ },
5561
+ "FunctionSecretWriteResult": {
5562
+ "type": "object",
5563
+ "description": "Returned by POST and PUT secret routes.",
5564
+ "properties": {
5565
+ "key": {
5566
+ "type": "string"
5567
+ },
5568
+ "created_at": {
5569
+ "type": "string",
5570
+ "format": "date-time"
5571
+ },
5572
+ "updated_at": {
5573
+ "type": "string",
5574
+ "format": "date-time"
5575
+ },
5576
+ "created": {
5577
+ "type": "boolean",
5578
+ "description": "True if this call inserted a new row, false if it updated an existing one."
5579
+ }
5580
+ },
5581
+ "required": [
5582
+ "key",
5583
+ "created_at",
5584
+ "updated_at",
5585
+ "created"
5586
+ ]
4321
5587
  }
4322
5588
  }
4323
5589
  }