@epilot/integration-toolkit-client 1.1.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/openapi.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.0.3",
3
3
  "info": {
4
4
  "title": "Integration Toolkit API",
5
- "version": "1.0.12",
5
+ "version": "1.2.0",
6
6
  "description": "API for integrating with external systems in a standardised way."
7
7
  },
8
8
  "tags": [
@@ -2378,21 +2378,25 @@
2378
2378
  }
2379
2379
  }
2380
2380
  },
2381
- "/v1/integrations/{integrationId}/monitoring/access-logs": {
2381
+ "/v1/integrations/{integrationId}/outbound/messages/poll": {
2382
2382
  "post": {
2383
- "operationId": "queryAccessLogs",
2384
- "summary": "queryAccessLogs",
2385
- "description": "Query API access logs for a specific integration's organization.\nReturns access token usage analytics filtered by user_id (access token).\nSupports infinite scroll pagination with cursor-based navigation.\n",
2383
+ "operationId": "pollOutboundMessages",
2384
+ "summary": "pollOutboundMessages",
2385
+ "description": "Poll outbound messages for an integration's poll-mode use cases.\nTakes a lease on the head-of-line batch of the integration's FIFO stream:\nthe returned messages stay invisible to subsequent polls until they are\nacknowledged or the visibility timeout elapses. POST because taking a\nlease mutates server state — auto-retrying middleware must not burn\nleases. One in-flight batch per stream: while a lease is active (or\nanother poll wins the race), the response is an empty batch\n(`messages: []`), not an error. Requires the `integration:consume` grant.\n",
2386
2386
  "tags": [
2387
- "monitoring",
2388
2387
  "integrations"
2389
2388
  ],
2389
+ "security": [
2390
+ {
2391
+ "EpilotAuth": []
2392
+ }
2393
+ ],
2390
2394
  "parameters": [
2391
2395
  {
2392
2396
  "name": "integrationId",
2393
2397
  "in": "path",
2394
2398
  "required": true,
2395
- "description": "The integration ID (used for tenant authorization)",
2399
+ "description": "The integration ID",
2396
2400
  "schema": {
2397
2401
  "type": "string",
2398
2402
  "format": "uuid"
@@ -2400,18 +2404,25 @@
2400
2404
  }
2401
2405
  ],
2402
2406
  "requestBody": {
2403
- "required": true,
2407
+ "required": false,
2404
2408
  "content": {
2405
2409
  "application/json": {
2406
2410
  "schema": {
2407
- "$ref": "#/components/schemas/QueryAccessLogsRequest"
2411
+ "$ref": "#/components/schemas/PollOutboundMessagesRequest"
2408
2412
  }
2409
2413
  }
2410
2414
  }
2411
2415
  },
2412
2416
  "responses": {
2413
2417
  "200": {
2414
- "$ref": "#/components/responses/QueryAccessLogsResponse"
2418
+ "description": "Leased batch of outbound messages (possibly empty)",
2419
+ "content": {
2420
+ "application/json": {
2421
+ "schema": {
2422
+ "$ref": "#/components/schemas/PollOutboundMessagesResponse"
2423
+ }
2424
+ }
2425
+ }
2415
2426
  },
2416
2427
  "400": {
2417
2428
  "$ref": "#/components/responses/BadRequest"
@@ -2419,6 +2430,9 @@
2419
2430
  "401": {
2420
2431
  "$ref": "#/components/responses/Unauthorized"
2421
2432
  },
2433
+ "403": {
2434
+ "$ref": "#/components/responses/Forbidden"
2435
+ },
2422
2436
  "404": {
2423
2437
  "$ref": "#/components/responses/NotFound"
2424
2438
  },
@@ -2428,15 +2442,19 @@
2428
2442
  }
2429
2443
  }
2430
2444
  },
2431
- "/v1/integrations/{integrationId}/monitoring/outbound-events": {
2445
+ "/v1/integrations/{integrationId}/outbound/messages/ack": {
2432
2446
  "post": {
2433
- "operationId": "queryOutboundMonitoringEvents",
2434
- "summary": "queryOutboundMonitoringEvents",
2435
- "description": "Query outbound monitoring events for a specific integration.\nReturns detailed information about outbound event deliveries,\nfiltered by event_name (event_catalog_event) linked to the integration's outbound use cases.\n",
2447
+ "operationId": "ackOutboundMessages",
2448
+ "summary": "ackOutboundMessages",
2449
+ "description": "Acknowledge polled outbound messages. Acks are validated against the\nactive lease and committed as a prefix-contiguous cursor advance:\nmessages must be acknowledged in stream order. Out-of-order acks past\nthe first gap are rejected per id (`out_of_order`), acks with an\noutdated lease token are rejected (`stale_lease`), and unknown ids are\nrejected (`not_found`). Acknowledged messages are never delivered\nagain. Requires the `integration:consume` grant.\n",
2436
2450
  "tags": [
2437
- "monitoring",
2438
2451
  "integrations"
2439
2452
  ],
2453
+ "security": [
2454
+ {
2455
+ "EpilotAuth": []
2456
+ }
2457
+ ],
2440
2458
  "parameters": [
2441
2459
  {
2442
2460
  "name": "integrationId",
@@ -2454,14 +2472,21 @@
2454
2472
  "content": {
2455
2473
  "application/json": {
2456
2474
  "schema": {
2457
- "$ref": "#/components/schemas/QueryOutboundMonitoringEventsRequest"
2475
+ "$ref": "#/components/schemas/AckOutboundMessagesRequest"
2458
2476
  }
2459
2477
  }
2460
2478
  }
2461
2479
  },
2462
2480
  "responses": {
2463
2481
  "200": {
2464
- "$ref": "#/components/responses/QueryOutboundMonitoringEventsResponse"
2482
+ "description": "Per-id acknowledgement results",
2483
+ "content": {
2484
+ "application/json": {
2485
+ "schema": {
2486
+ "$ref": "#/components/schemas/AckOutboundMessagesResponse"
2487
+ }
2488
+ }
2489
+ }
2465
2490
  },
2466
2491
  "400": {
2467
2492
  "$ref": "#/components/responses/BadRequest"
@@ -2469,6 +2494,9 @@
2469
2494
  "401": {
2470
2495
  "$ref": "#/components/responses/Unauthorized"
2471
2496
  },
2497
+ "403": {
2498
+ "$ref": "#/components/responses/Forbidden"
2499
+ },
2472
2500
  "404": {
2473
2501
  "$ref": "#/components/responses/NotFound"
2474
2502
  },
@@ -2478,15 +2506,19 @@
2478
2506
  }
2479
2507
  }
2480
2508
  },
2481
- "/v2/integrations/{integrationId}/monitoring/events": {
2482
- "post": {
2483
- "operationId": "queryMonitoringEventsV2",
2484
- "summary": "queryMonitoringEventsV2",
2485
- "description": "Query monitoring events from the unified erp_monitoring_v2 table.\nReturns all event types (inbound, outbound, file_proxy, etc.) in a single list.\nReplaces the separate v1 inbound-events and outbound-events endpoints.\n",
2509
+ "/v1/integrations/{integrationId}/outbound/messages/dlq": {
2510
+ "get": {
2511
+ "operationId": "listOutboundDlqMessages",
2512
+ "summary": "listOutboundDlqMessages",
2513
+ "description": "List an integration's dead-lettered outbound queue messages\n(poison_policy enforcement and operator skips move messages here).\nOperator endpoint requires the `integration:manage` grant. Message\npayloads are NOT included in listings: entries are keyed by the\nopaque message id and carry delivery metadata only. Paginated via an\nopaque `next_token`.\n",
2486
2514
  "tags": [
2487
- "monitoring",
2488
2515
  "integrations"
2489
2516
  ],
2517
+ "security": [
2518
+ {
2519
+ "EpilotAuth": []
2520
+ }
2521
+ ],
2490
2522
  "parameters": [
2491
2523
  {
2492
2524
  "name": "integrationId",
@@ -2497,21 +2529,39 @@
2497
2529
  "type": "string",
2498
2530
  "format": "uuid"
2499
2531
  }
2500
- }
2501
- ],
2502
- "requestBody": {
2503
- "required": true,
2504
- "content": {
2505
- "application/json": {
2506
- "schema": {
2507
- "$ref": "#/components/schemas/QueryMonitoringEventsV2Request"
2508
- }
2532
+ },
2533
+ {
2534
+ "name": "limit",
2535
+ "in": "query",
2536
+ "required": false,
2537
+ "description": "Maximum number of DLQ entries to return",
2538
+ "schema": {
2539
+ "type": "integer",
2540
+ "minimum": 1,
2541
+ "maximum": 100,
2542
+ "default": 25
2543
+ }
2544
+ },
2545
+ {
2546
+ "name": "next_token",
2547
+ "in": "query",
2548
+ "required": false,
2549
+ "description": "Opaque pagination token from a previous response",
2550
+ "schema": {
2551
+ "type": "string"
2509
2552
  }
2510
2553
  }
2511
- },
2554
+ ],
2512
2555
  "responses": {
2513
2556
  "200": {
2514
- "$ref": "#/components/responses/QueryMonitoringEventsV2Response"
2557
+ "description": "Page of dead-lettered messages",
2558
+ "content": {
2559
+ "application/json": {
2560
+ "schema": {
2561
+ "$ref": "#/components/schemas/OutboundDlqListResponse"
2562
+ }
2563
+ }
2564
+ }
2515
2565
  },
2516
2566
  "400": {
2517
2567
  "$ref": "#/components/responses/BadRequest"
@@ -2519,6 +2569,9 @@
2519
2569
  "401": {
2520
2570
  "$ref": "#/components/responses/Unauthorized"
2521
2571
  },
2572
+ "403": {
2573
+ "$ref": "#/components/responses/Forbidden"
2574
+ },
2522
2575
  "404": {
2523
2576
  "$ref": "#/components/responses/NotFound"
2524
2577
  },
@@ -2528,15 +2581,19 @@
2528
2581
  }
2529
2582
  }
2530
2583
  },
2531
- "/v2/integrations/{integrationId}/monitoring/stats": {
2584
+ "/v1/integrations/{integrationId}/outbound/messages/dlq/redrive": {
2532
2585
  "post": {
2533
- "operationId": "getMonitoringStatsV2",
2534
- "summary": "getMonitoringStatsV2",
2535
- "description": "Get aggregated statistics from the unified erp_monitoring_v2 table.\nReturns combined metrics for all event types with optional breakdowns.\n",
2586
+ "operationId": "redriveOutboundDlqMessages",
2587
+ "summary": "redriveOutboundDlqMessages",
2588
+ "description": "Redrive selected dead-lettered messages back into the live stream.\nOperator endpoint — requires the `integration:manage` grant.\nA redriven message is re-enqueued at the tail with a new id and\nsequence — it is delivered out of its original per-entity order (the\nstream has moved on); this is inherent to redrive and matches SQS DLQ\nsemantics. The redriven copy starts with zero delivery attempts and a\nfresh retention window; the original DLQ entry is removed. Per-id\nresults report `redriven` or `not_found` (unknown ids, or entries\nconcurrently redriven/expired).\n",
2536
2589
  "tags": [
2537
- "monitoring",
2538
2590
  "integrations"
2539
2591
  ],
2592
+ "security": [
2593
+ {
2594
+ "EpilotAuth": []
2595
+ }
2596
+ ],
2540
2597
  "parameters": [
2541
2598
  {
2542
2599
  "name": "integrationId",
@@ -2554,14 +2611,21 @@
2554
2611
  "content": {
2555
2612
  "application/json": {
2556
2613
  "schema": {
2557
- "$ref": "#/components/schemas/GetMonitoringStatsV2Request"
2614
+ "$ref": "#/components/schemas/RedriveOutboundDlqRequest"
2558
2615
  }
2559
2616
  }
2560
2617
  }
2561
2618
  },
2562
2619
  "responses": {
2563
2620
  "200": {
2564
- "$ref": "#/components/responses/GetMonitoringStatsV2Response"
2621
+ "description": "Per-id redrive results",
2622
+ "content": {
2623
+ "application/json": {
2624
+ "schema": {
2625
+ "$ref": "#/components/schemas/RedriveOutboundDlqResponse"
2626
+ }
2627
+ }
2628
+ }
2565
2629
  },
2566
2630
  "400": {
2567
2631
  "$ref": "#/components/responses/BadRequest"
@@ -2569,6 +2633,9 @@
2569
2633
  "401": {
2570
2634
  "$ref": "#/components/responses/Unauthorized"
2571
2635
  },
2636
+ "403": {
2637
+ "$ref": "#/components/responses/Forbidden"
2638
+ },
2572
2639
  "404": {
2573
2640
  "$ref": "#/components/responses/NotFound"
2574
2641
  },
@@ -2578,15 +2645,19 @@
2578
2645
  }
2579
2646
  }
2580
2647
  },
2581
- "/v2/integrations/{integrationId}/monitoring/time-series": {
2648
+ "/v1/integrations/{integrationId}/outbound/messages/unblock": {
2582
2649
  "post": {
2583
- "operationId": "getMonitoringTimeSeriesV2",
2584
- "summary": "getMonitoringTimeSeriesV2",
2585
- "description": "Get time-series aggregated event counts from the unified erp_monitoring_v2 table.\nReturns bucketed counts for chart rendering.\n",
2650
+ "operationId": "unblockOutboundStream",
2651
+ "summary": "unblockOutboundStream",
2652
+ "description": "Unblock an integration's outbound stream halted by the `block`\npoison policy: skips (dead-letters) the current blocked head message,\nemitting MSG_DEAD_LETTERED and letting the next message become the\nhead. Operator endpoint — requires the `integration:manage` grant.\nReturns `unblocked: false` as a no-op when the stream is not\ncurrently blocked (or the state moved concurrently) — safe to retry.\n",
2586
2653
  "tags": [
2587
- "monitoring",
2588
2654
  "integrations"
2589
2655
  ],
2656
+ "security": [
2657
+ {
2658
+ "EpilotAuth": []
2659
+ }
2660
+ ],
2590
2661
  "parameters": [
2591
2662
  {
2592
2663
  "name": "integrationId",
@@ -2600,18 +2671,25 @@
2600
2671
  }
2601
2672
  ],
2602
2673
  "requestBody": {
2603
- "required": true,
2674
+ "required": false,
2604
2675
  "content": {
2605
2676
  "application/json": {
2606
2677
  "schema": {
2607
- "$ref": "#/components/schemas/GetMonitoringTimeSeriesV2Request"
2678
+ "$ref": "#/components/schemas/UnblockOutboundStreamRequest"
2608
2679
  }
2609
2680
  }
2610
2681
  }
2611
2682
  },
2612
2683
  "responses": {
2613
2684
  "200": {
2614
- "$ref": "#/components/responses/GetMonitoringTimeSeriesV2Response"
2685
+ "description": "Unblock outcome",
2686
+ "content": {
2687
+ "application/json": {
2688
+ "schema": {
2689
+ "$ref": "#/components/schemas/UnblockOutboundStreamResponse"
2690
+ }
2691
+ }
2692
+ }
2615
2693
  },
2616
2694
  "400": {
2617
2695
  "$ref": "#/components/responses/BadRequest"
@@ -2619,6 +2697,9 @@
2619
2697
  "401": {
2620
2698
  "$ref": "#/components/responses/Unauthorized"
2621
2699
  },
2700
+ "403": {
2701
+ "$ref": "#/components/responses/Forbidden"
2702
+ },
2622
2703
  "404": {
2623
2704
  "$ref": "#/components/responses/NotFound"
2624
2705
  },
@@ -2628,11 +2709,11 @@
2628
2709
  }
2629
2710
  }
2630
2711
  },
2631
- "/v2/integrations/{integrationId}/monitoring/events/{eventId}/associated": {
2632
- "get": {
2633
- "operationId": "getAssociatedMonitoringEvents",
2634
- "summary": "getAssociatedMonitoringEvents",
2635
- "description": "Returns all monitoring events sharing the same event_id, ordered chronologically.\nAlso includes the original inbound event payload from erp_incoming_events if available.\nUsed to display a full event trace/timeline.\n",
2712
+ "/v1/integrations/{integrationId}/monitoring/access-logs": {
2713
+ "post": {
2714
+ "operationId": "queryAccessLogs",
2715
+ "summary": "queryAccessLogs",
2716
+ "description": "Query API access logs for a specific integration's organization.\nReturns access token usage analytics filtered by user_id (access token).\nSupports infinite scroll pagination with cursor-based navigation.\n",
2636
2717
  "tags": [
2637
2718
  "monitoring",
2638
2719
  "integrations"
@@ -2642,25 +2723,26 @@
2642
2723
  "name": "integrationId",
2643
2724
  "in": "path",
2644
2725
  "required": true,
2645
- "description": "The integration ID",
2726
+ "description": "The integration ID (used for tenant authorization)",
2646
2727
  "schema": {
2647
2728
  "type": "string",
2648
2729
  "format": "uuid"
2649
2730
  }
2650
- },
2651
- {
2652
- "name": "eventId",
2653
- "in": "path",
2654
- "required": true,
2655
- "description": "The event ID to get associated events for",
2656
- "schema": {
2657
- "type": "string"
2658
- }
2659
2731
  }
2660
2732
  ],
2733
+ "requestBody": {
2734
+ "required": true,
2735
+ "content": {
2736
+ "application/json": {
2737
+ "schema": {
2738
+ "$ref": "#/components/schemas/QueryAccessLogsRequest"
2739
+ }
2740
+ }
2741
+ }
2742
+ },
2661
2743
  "responses": {
2662
2744
  "200": {
2663
- "$ref": "#/components/responses/GetAssociatedMonitoringEventsResponse"
2745
+ "$ref": "#/components/responses/QueryAccessLogsResponse"
2664
2746
  },
2665
2747
  "400": {
2666
2748
  "$ref": "#/components/responses/BadRequest"
@@ -2668,67 +2750,84 @@
2668
2750
  "401": {
2669
2751
  "$ref": "#/components/responses/Unauthorized"
2670
2752
  },
2753
+ "404": {
2754
+ "$ref": "#/components/responses/NotFound"
2755
+ },
2671
2756
  "500": {
2672
2757
  "$ref": "#/components/responses/InternalServerError"
2673
2758
  }
2674
2759
  }
2675
2760
  }
2676
2761
  },
2677
- "/v1/integrations/secure-proxies": {
2678
- "get": {
2679
- "operationId": "listSecureProxies",
2680
- "summary": "List all secure proxy use cases",
2681
- "description": "Lists all secure_proxy use cases across all integrations for the authenticated organization.\nReturns minimal data suitable for dropdowns and selection UIs.\n",
2762
+ "/v1/integrations/{integrationId}/monitoring/outbound-events": {
2763
+ "post": {
2764
+ "operationId": "queryOutboundMonitoringEvents",
2765
+ "summary": "queryOutboundMonitoringEvents",
2766
+ "description": "Query outbound monitoring events for a specific integration.\nReturns detailed information about outbound event deliveries,\nfiltered by event_name (event_catalog_event) linked to the integration's outbound use cases.\n",
2682
2767
  "tags": [
2768
+ "monitoring",
2683
2769
  "integrations"
2684
2770
  ],
2685
- "security": [
2771
+ "parameters": [
2686
2772
  {
2687
- "EpilotAuth": []
2773
+ "name": "integrationId",
2774
+ "in": "path",
2775
+ "required": true,
2776
+ "description": "The integration ID",
2777
+ "schema": {
2778
+ "type": "string",
2779
+ "format": "uuid"
2780
+ }
2688
2781
  }
2689
2782
  ],
2690
- "responses": {
2691
- "200": {
2692
- "description": "Successfully retrieved secure proxy use cases",
2693
- "content": {
2694
- "application/json": {
2695
- "schema": {
2696
- "type": "object",
2697
- "required": [
2698
- "secure_proxies"
2699
- ],
2700
- "properties": {
2701
- "secure_proxies": {
2702
- "type": "array",
2703
- "items": {
2704
- "$ref": "#/components/schemas/SecureProxySummary"
2705
- }
2706
- }
2707
- }
2708
- }
2783
+ "requestBody": {
2784
+ "required": true,
2785
+ "content": {
2786
+ "application/json": {
2787
+ "schema": {
2788
+ "$ref": "#/components/schemas/QueryOutboundMonitoringEventsRequest"
2709
2789
  }
2710
2790
  }
2791
+ }
2792
+ },
2793
+ "responses": {
2794
+ "200": {
2795
+ "$ref": "#/components/responses/QueryOutboundMonitoringEventsResponse"
2796
+ },
2797
+ "400": {
2798
+ "$ref": "#/components/responses/BadRequest"
2711
2799
  },
2712
2800
  "401": {
2713
2801
  "$ref": "#/components/responses/Unauthorized"
2714
2802
  },
2803
+ "404": {
2804
+ "$ref": "#/components/responses/NotFound"
2805
+ },
2715
2806
  "500": {
2716
2807
  "$ref": "#/components/responses/InternalServerError"
2717
2808
  }
2718
2809
  }
2719
2810
  }
2720
2811
  },
2721
- "/v1/secure-proxy": {
2812
+ "/v2/integrations/{integrationId}/monitoring/events": {
2722
2813
  "post": {
2723
- "operationId": "secureProxy",
2724
- "summary": "Proxy HTTP request through secure VPC",
2725
- "description": "Routes an HTTP request through a VPC with either static IP egress or VPN secure link access.\nThe VPC mode is determined by the referenced secure_proxy use case configuration.\nFor secure_link mode, the target URL must match the use case's allowed_domains whitelist.\n",
2814
+ "operationId": "queryMonitoringEventsV2",
2815
+ "summary": "queryMonitoringEventsV2",
2816
+ "description": "Query monitoring events from the unified erp_monitoring_v2 table.\nReturns all event types (inbound, outbound, file_proxy, etc.) in a single list.\nReplaces the separate v1 inbound-events and outbound-events endpoints.\n",
2726
2817
  "tags": [
2727
- "proxy"
2818
+ "monitoring",
2819
+ "integrations"
2728
2820
  ],
2729
- "security": [
2821
+ "parameters": [
2730
2822
  {
2731
- "EpilotAuth": []
2823
+ "name": "integrationId",
2824
+ "in": "path",
2825
+ "required": true,
2826
+ "description": "The integration ID",
2827
+ "schema": {
2828
+ "type": "string",
2829
+ "format": "uuid"
2830
+ }
2732
2831
  }
2733
2832
  ],
2734
2833
  "requestBody": {
@@ -2736,15 +2835,247 @@
2736
2835
  "content": {
2737
2836
  "application/json": {
2738
2837
  "schema": {
2739
- "$ref": "#/components/schemas/SecureProxyRequest"
2838
+ "$ref": "#/components/schemas/QueryMonitoringEventsV2Request"
2740
2839
  }
2741
2840
  }
2742
2841
  }
2743
2842
  },
2744
2843
  "responses": {
2745
2844
  "200": {
2746
- "description": "Proxied response from the target URL",
2747
- "content": {
2845
+ "$ref": "#/components/responses/QueryMonitoringEventsV2Response"
2846
+ },
2847
+ "400": {
2848
+ "$ref": "#/components/responses/BadRequest"
2849
+ },
2850
+ "401": {
2851
+ "$ref": "#/components/responses/Unauthorized"
2852
+ },
2853
+ "404": {
2854
+ "$ref": "#/components/responses/NotFound"
2855
+ },
2856
+ "500": {
2857
+ "$ref": "#/components/responses/InternalServerError"
2858
+ }
2859
+ }
2860
+ }
2861
+ },
2862
+ "/v2/integrations/{integrationId}/monitoring/stats": {
2863
+ "post": {
2864
+ "operationId": "getMonitoringStatsV2",
2865
+ "summary": "getMonitoringStatsV2",
2866
+ "description": "Get aggregated statistics from the unified erp_monitoring_v2 table.\nReturns combined metrics for all event types with optional breakdowns.\n",
2867
+ "tags": [
2868
+ "monitoring",
2869
+ "integrations"
2870
+ ],
2871
+ "parameters": [
2872
+ {
2873
+ "name": "integrationId",
2874
+ "in": "path",
2875
+ "required": true,
2876
+ "description": "The integration ID",
2877
+ "schema": {
2878
+ "type": "string",
2879
+ "format": "uuid"
2880
+ }
2881
+ }
2882
+ ],
2883
+ "requestBody": {
2884
+ "required": true,
2885
+ "content": {
2886
+ "application/json": {
2887
+ "schema": {
2888
+ "$ref": "#/components/schemas/GetMonitoringStatsV2Request"
2889
+ }
2890
+ }
2891
+ }
2892
+ },
2893
+ "responses": {
2894
+ "200": {
2895
+ "$ref": "#/components/responses/GetMonitoringStatsV2Response"
2896
+ },
2897
+ "400": {
2898
+ "$ref": "#/components/responses/BadRequest"
2899
+ },
2900
+ "401": {
2901
+ "$ref": "#/components/responses/Unauthorized"
2902
+ },
2903
+ "404": {
2904
+ "$ref": "#/components/responses/NotFound"
2905
+ },
2906
+ "500": {
2907
+ "$ref": "#/components/responses/InternalServerError"
2908
+ }
2909
+ }
2910
+ }
2911
+ },
2912
+ "/v2/integrations/{integrationId}/monitoring/time-series": {
2913
+ "post": {
2914
+ "operationId": "getMonitoringTimeSeriesV2",
2915
+ "summary": "getMonitoringTimeSeriesV2",
2916
+ "description": "Get time-series aggregated event counts from the unified erp_monitoring_v2 table.\nReturns bucketed counts for chart rendering.\n",
2917
+ "tags": [
2918
+ "monitoring",
2919
+ "integrations"
2920
+ ],
2921
+ "parameters": [
2922
+ {
2923
+ "name": "integrationId",
2924
+ "in": "path",
2925
+ "required": true,
2926
+ "description": "The integration ID",
2927
+ "schema": {
2928
+ "type": "string",
2929
+ "format": "uuid"
2930
+ }
2931
+ }
2932
+ ],
2933
+ "requestBody": {
2934
+ "required": true,
2935
+ "content": {
2936
+ "application/json": {
2937
+ "schema": {
2938
+ "$ref": "#/components/schemas/GetMonitoringTimeSeriesV2Request"
2939
+ }
2940
+ }
2941
+ }
2942
+ },
2943
+ "responses": {
2944
+ "200": {
2945
+ "$ref": "#/components/responses/GetMonitoringTimeSeriesV2Response"
2946
+ },
2947
+ "400": {
2948
+ "$ref": "#/components/responses/BadRequest"
2949
+ },
2950
+ "401": {
2951
+ "$ref": "#/components/responses/Unauthorized"
2952
+ },
2953
+ "404": {
2954
+ "$ref": "#/components/responses/NotFound"
2955
+ },
2956
+ "500": {
2957
+ "$ref": "#/components/responses/InternalServerError"
2958
+ }
2959
+ }
2960
+ }
2961
+ },
2962
+ "/v2/integrations/{integrationId}/monitoring/events/{eventId}/associated": {
2963
+ "get": {
2964
+ "operationId": "getAssociatedMonitoringEvents",
2965
+ "summary": "getAssociatedMonitoringEvents",
2966
+ "description": "Returns all monitoring events sharing the same event_id, ordered chronologically.\nAlso includes the original inbound event payload from erp_incoming_events if available.\nUsed to display a full event trace/timeline.\n",
2967
+ "tags": [
2968
+ "monitoring",
2969
+ "integrations"
2970
+ ],
2971
+ "parameters": [
2972
+ {
2973
+ "name": "integrationId",
2974
+ "in": "path",
2975
+ "required": true,
2976
+ "description": "The integration ID",
2977
+ "schema": {
2978
+ "type": "string",
2979
+ "format": "uuid"
2980
+ }
2981
+ },
2982
+ {
2983
+ "name": "eventId",
2984
+ "in": "path",
2985
+ "required": true,
2986
+ "description": "The event ID to get associated events for",
2987
+ "schema": {
2988
+ "type": "string"
2989
+ }
2990
+ }
2991
+ ],
2992
+ "responses": {
2993
+ "200": {
2994
+ "$ref": "#/components/responses/GetAssociatedMonitoringEventsResponse"
2995
+ },
2996
+ "400": {
2997
+ "$ref": "#/components/responses/BadRequest"
2998
+ },
2999
+ "401": {
3000
+ "$ref": "#/components/responses/Unauthorized"
3001
+ },
3002
+ "500": {
3003
+ "$ref": "#/components/responses/InternalServerError"
3004
+ }
3005
+ }
3006
+ }
3007
+ },
3008
+ "/v1/integrations/secure-proxies": {
3009
+ "get": {
3010
+ "operationId": "listSecureProxies",
3011
+ "summary": "List all secure proxy use cases",
3012
+ "description": "Lists all secure_proxy use cases across all integrations for the authenticated organization.\nReturns minimal data suitable for dropdowns and selection UIs.\n",
3013
+ "tags": [
3014
+ "integrations"
3015
+ ],
3016
+ "security": [
3017
+ {
3018
+ "EpilotAuth": []
3019
+ }
3020
+ ],
3021
+ "responses": {
3022
+ "200": {
3023
+ "description": "Successfully retrieved secure proxy use cases",
3024
+ "content": {
3025
+ "application/json": {
3026
+ "schema": {
3027
+ "type": "object",
3028
+ "required": [
3029
+ "secure_proxies"
3030
+ ],
3031
+ "properties": {
3032
+ "secure_proxies": {
3033
+ "type": "array",
3034
+ "items": {
3035
+ "$ref": "#/components/schemas/SecureProxySummary"
3036
+ }
3037
+ }
3038
+ }
3039
+ }
3040
+ }
3041
+ }
3042
+ },
3043
+ "401": {
3044
+ "$ref": "#/components/responses/Unauthorized"
3045
+ },
3046
+ "500": {
3047
+ "$ref": "#/components/responses/InternalServerError"
3048
+ }
3049
+ }
3050
+ }
3051
+ },
3052
+ "/v1/secure-proxy": {
3053
+ "post": {
3054
+ "operationId": "secureProxy",
3055
+ "summary": "Proxy HTTP request through secure VPC",
3056
+ "description": "Routes an HTTP request through a VPC with either static IP egress or VPN secure link access.\nThe VPC mode is determined by the referenced secure_proxy use case configuration.\nFor secure_link mode, the target URL must match the use case's allowed_domains whitelist.\n",
3057
+ "tags": [
3058
+ "proxy"
3059
+ ],
3060
+ "security": [
3061
+ {
3062
+ "EpilotAuth": []
3063
+ }
3064
+ ],
3065
+ "requestBody": {
3066
+ "required": true,
3067
+ "content": {
3068
+ "application/json": {
3069
+ "schema": {
3070
+ "$ref": "#/components/schemas/SecureProxyRequest"
3071
+ }
3072
+ }
3073
+ }
3074
+ },
3075
+ "responses": {
3076
+ "200": {
3077
+ "description": "Proxied response from the target URL",
3078
+ "content": {
2748
3079
  "application/json": {
2749
3080
  "schema": {
2750
3081
  "$ref": "#/components/schemas/SecureProxyResponse"
@@ -6462,11 +6793,10 @@
6462
6793
  "type": "object",
6463
6794
  "required": [
6464
6795
  "name",
6465
- "jsonata_expression",
6466
6796
  "enabled",
6467
6797
  "delivery"
6468
6798
  ],
6469
- "description": "A mapping that transforms an event and delivers it to a webhook",
6799
+ "description": "A mapping that delivers an event to an external system — either pushed to a webhook (with a JSONata payload transformation) or made available on the pull-based poll queue (raw event payload, no transformation)",
6470
6800
  "properties": {
6471
6801
  "id": {
6472
6802
  "type": "string",
@@ -6480,7 +6810,7 @@
6480
6810
  },
6481
6811
  "jsonata_expression": {
6482
6812
  "type": "string",
6483
- "description": "JSONata expression to transform the event payload",
6813
+ "description": "JSONata expression to transform the event payload. Required for webhook delivery; ignored for poll delivery.",
6484
6814
  "example": "{ \"id\": entity._id, \"customer\": entity.customer_name }"
6485
6815
  },
6486
6816
  "enabled": {
@@ -6504,19 +6834,37 @@
6504
6834
  }
6505
6835
  },
6506
6836
  "DeliveryConfig": {
6837
+ "description": "Configuration for how the event should be delivered. webhook = push delivery via svc-webhooks (JSONata-transformed payload); poll = pull-based queue delivery where the consumer fetches items via the poll API (raw event payload)",
6838
+ "oneOf": [
6839
+ {
6840
+ "$ref": "#/components/schemas/WebhookDeliveryConfig"
6841
+ },
6842
+ {
6843
+ "$ref": "#/components/schemas/PollDeliveryConfig"
6844
+ }
6845
+ ],
6846
+ "discriminator": {
6847
+ "propertyName": "type",
6848
+ "mapping": {
6849
+ "webhook": "#/components/schemas/WebhookDeliveryConfig",
6850
+ "poll": "#/components/schemas/PollDeliveryConfig"
6851
+ }
6852
+ }
6853
+ },
6854
+ "WebhookDeliveryConfig": {
6507
6855
  "type": "object",
6508
6856
  "required": [
6509
6857
  "type",
6510
6858
  "webhook_id"
6511
6859
  ],
6512
- "description": "Configuration for how the transformed event should be delivered",
6860
+ "description": "Push delivery of the transformed event to a webhook via svc-webhooks",
6513
6861
  "properties": {
6514
6862
  "type": {
6515
6863
  "type": "string",
6516
6864
  "enum": [
6517
6865
  "webhook"
6518
6866
  ],
6519
- "description": "Delivery mechanism type (currently only webhook is supported)"
6867
+ "description": "Delivery mechanism type"
6520
6868
  },
6521
6869
  "webhook_id": {
6522
6870
  "type": "string",
@@ -6532,6 +6880,45 @@
6532
6880
  }
6533
6881
  }
6534
6882
  },
6883
+ "PollDeliveryConfig": {
6884
+ "type": "object",
6885
+ "required": [
6886
+ "type"
6887
+ ],
6888
+ "description": "Pull-based queue delivery. Items carry the raw standardized event-catalog payload; no JSONata mapping is applied in poll mode. Consumers fetch and acknowledge items via the poll API.",
6889
+ "properties": {
6890
+ "type": {
6891
+ "type": "string",
6892
+ "enum": [
6893
+ "poll"
6894
+ ],
6895
+ "description": "Delivery mechanism type"
6896
+ },
6897
+ "retention_days": {
6898
+ "type": "integer",
6899
+ "minimum": 1,
6900
+ "maximum": 90,
6901
+ "default": 30,
6902
+ "description": "How long undelivered queue items are retained before expiry"
6903
+ },
6904
+ "poison_policy": {
6905
+ "type": "string",
6906
+ "enum": [
6907
+ "dead_letter",
6908
+ "block"
6909
+ ],
6910
+ "default": "dead_letter",
6911
+ "description": "What happens when an item exhausts max_delivery_attempts: dead_letter routes the exhausted item to the dead-letter queue; block halts the queue until operator/consumer action. Enforcement lands with the queue consumer (Phase 10) — this field defines the contract."
6912
+ },
6913
+ "max_delivery_attempts": {
6914
+ "type": "integer",
6915
+ "minimum": 1,
6916
+ "maximum": 100,
6917
+ "default": 5,
6918
+ "description": "Maximum delivery attempts before the poison_policy is applied"
6919
+ }
6920
+ }
6921
+ },
6535
6922
  "OutboundStatusResponse": {
6536
6923
  "type": "object",
6537
6924
  "required": [
@@ -6599,6 +6986,52 @@
6599
6986
  "$ref": "#/components/schemas/OutboundConflict"
6600
6987
  },
6601
6988
  "description": "List of detected conflicts, if any"
6989
+ },
6990
+ "poll": {
6991
+ "$ref": "#/components/schemas/OutboundPollStatus"
6992
+ }
6993
+ }
6994
+ },
6995
+ "OutboundPollStatus": {
6996
+ "type": "object",
6997
+ "description": "Queue/consumer health for a poll-mode use case. Present only on use\ncases with a poll delivery mapping — webhook-only use cases are\nunaffected. Depth/age/DLQ numbers are first-page approximations.\n",
6998
+ "required": [
6999
+ "queue_depth",
7000
+ "oldest_unconsumed_age_seconds",
7001
+ "last_poll_at",
7002
+ "last_ack_at",
7003
+ "blocked",
7004
+ "dlq_count"
7005
+ ],
7006
+ "properties": {
7007
+ "queue_depth": {
7008
+ "type": "integer",
7009
+ "description": "Unconsumed messages attributable to this use case (first-page approximation)"
7010
+ },
7011
+ "oldest_unconsumed_age_seconds": {
7012
+ "type": "integer",
7013
+ "nullable": true,
7014
+ "description": "Age of the oldest unconsumed message in seconds — null when the queue is empty"
7015
+ },
7016
+ "last_poll_at": {
7017
+ "type": "string",
7018
+ "format": "date-time",
7019
+ "nullable": true,
7020
+ "description": "Timestamp of the last successful poll lease — null before the first poll"
7021
+ },
7022
+ "last_ack_at": {
7023
+ "type": "string",
7024
+ "format": "date-time",
7025
+ "nullable": true,
7026
+ "description": "Timestamp of the last committed acknowledgment — null before the first ack"
7027
+ },
7028
+ "blocked": {
7029
+ "type": "boolean",
7030
+ "description": "Whether the integration's outbound stream is currently halted by a\nblocked head message (poison_policy 'block'). Stream-level flag —\nthe same value is reported on every poll use case of the\nintegration, because the stream spans them.\n"
7031
+ },
7032
+ "dlq_count": {
7033
+ "type": "integer",
7034
+ "description": "Dead-lettered messages of this use case awaiting redrive or expiry (first-page approximation)"
6602
7035
  }
6603
7036
  }
6604
7037
  },
@@ -6636,9 +7069,11 @@
6636
7069
  "event_disabled",
6637
7070
  "all_webhooks_disabled",
6638
7071
  "event_enabled_while_disabled",
6639
- "webhook_enabled_while_disabled"
7072
+ "webhook_enabled_while_disabled",
7073
+ "stream_blocked",
7074
+ "dlq_items_present"
6640
7075
  ],
6641
- "description": "Type of conflict:\n- 'event_disabled': Event catalog event is disabled while use case is enabled\n- 'all_webhooks_disabled': All webhooks are disabled while use case is enabled\n- 'event_enabled_while_disabled': Event is enabled while use case is disabled\n- 'webhook_enabled_while_disabled': A webhook is enabled while use case is disabled\n"
7076
+ "description": "Type of conflict:\n- 'event_disabled': Event catalog event is disabled while use case is enabled\n- 'all_webhooks_disabled': All webhooks are disabled while use case is enabled\n- 'event_enabled_while_disabled': Event is enabled while use case is disabled\n- 'webhook_enabled_while_disabled': A webhook is enabled while use case is disabled\n- 'stream_blocked': The outbound stream is halted by a poison message awaiting operator action or consumer ack (poll mode)\n- 'dlq_items_present': Dead-lettered messages await redrive or expiry (poll mode)\n"
6642
7077
  },
6643
7078
  "webhookId": {
6644
7079
  "type": "string",
@@ -6650,6 +7085,320 @@
6650
7085
  }
6651
7086
  }
6652
7087
  },
7088
+ "PollOutboundMessagesRequest": {
7089
+ "type": "object",
7090
+ "additionalProperties": false,
7091
+ "properties": {
7092
+ "limit": {
7093
+ "type": "integer",
7094
+ "maximum": 100,
7095
+ "minimum": 1,
7096
+ "default": 10,
7097
+ "description": "Maximum number of messages to lease in this batch. The ~5.5 MB\nresponse cap may truncate the batch earlier when payloads are\nlarge — the leased run shrinks accordingly.\n"
7098
+ }
7099
+ }
7100
+ },
7101
+ "OutboundMessage": {
7102
+ "type": "object",
7103
+ "required": [
7104
+ "id",
7105
+ "lease_token",
7106
+ "use_case_id",
7107
+ "event_name",
7108
+ "event_id",
7109
+ "group",
7110
+ "payload",
7111
+ "enqueued_at"
7112
+ ],
7113
+ "properties": {
7114
+ "id": {
7115
+ "type": "string",
7116
+ "description": "Opaque message id (msg_…) — stable per message across leases"
7117
+ },
7118
+ "lease_token": {
7119
+ "type": "string",
7120
+ "description": "Opaque lease token (lt_…) — echo back on ack"
7121
+ },
7122
+ "use_case_id": {
7123
+ "type": "string",
7124
+ "description": "The poll-mode use case that produced this message"
7125
+ },
7126
+ "event_name": {
7127
+ "type": "string",
7128
+ "description": "Standardized event name (e.g. contract.updated)"
7129
+ },
7130
+ "event_id": {
7131
+ "type": "string",
7132
+ "description": "Unique id of the originating event"
7133
+ },
7134
+ "group": {
7135
+ "type": "string",
7136
+ "description": "Ordering group — messages sharing a group are strictly ordered,\ndistinct groups are independent. Constant \"0\" in v1.\n"
7137
+ },
7138
+ "payload": {
7139
+ "type": "object",
7140
+ "additionalProperties": true,
7141
+ "description": "The raw standardized event-catalog event, always inlined as-is"
7142
+ },
7143
+ "enqueued_at": {
7144
+ "type": "string",
7145
+ "format": "date-time",
7146
+ "description": "When the message was enqueued"
7147
+ }
7148
+ }
7149
+ },
7150
+ "PollOutboundMessagesResponse": {
7151
+ "type": "object",
7152
+ "required": [
7153
+ "messages",
7154
+ "visibility_timeout_seconds",
7155
+ "has_more"
7156
+ ],
7157
+ "properties": {
7158
+ "messages": {
7159
+ "type": "array",
7160
+ "items": {
7161
+ "$ref": "#/components/schemas/OutboundMessage"
7162
+ },
7163
+ "description": "The leased batch in strict stream order (empty when contended or drained)"
7164
+ },
7165
+ "visibility_timeout_seconds": {
7166
+ "type": "integer",
7167
+ "description": "Effective visibility timeout for this lease — a per-integration\nserver-side setting (default 300 seconds)\n"
7168
+ },
7169
+ "has_more": {
7170
+ "type": "boolean",
7171
+ "description": "Whether more messages are available beyond this batch"
7172
+ }
7173
+ }
7174
+ },
7175
+ "AckOutboundMessagesRequest": {
7176
+ "type": "object",
7177
+ "required": [
7178
+ "acks"
7179
+ ],
7180
+ "properties": {
7181
+ "acks": {
7182
+ "type": "array",
7183
+ "minItems": 1,
7184
+ "maxItems": 100,
7185
+ "items": {
7186
+ "type": "object",
7187
+ "additionalProperties": false,
7188
+ "required": [
7189
+ "id",
7190
+ "lease_token"
7191
+ ],
7192
+ "properties": {
7193
+ "id": {
7194
+ "type": "string",
7195
+ "description": "The message id (msg_…) to acknowledge"
7196
+ },
7197
+ "lease_token": {
7198
+ "type": "string",
7199
+ "description": "The lease token (lt_…) returned by the poll that leased this message"
7200
+ }
7201
+ }
7202
+ }
7203
+ }
7204
+ }
7205
+ },
7206
+ "AckResult": {
7207
+ "type": "object",
7208
+ "required": [
7209
+ "id",
7210
+ "status"
7211
+ ],
7212
+ "properties": {
7213
+ "id": {
7214
+ "type": "string",
7215
+ "description": "The acknowledged message id"
7216
+ },
7217
+ "status": {
7218
+ "type": "string",
7219
+ "enum": [
7220
+ "accepted",
7221
+ "rejected"
7222
+ ]
7223
+ },
7224
+ "reason": {
7225
+ "type": "string",
7226
+ "enum": [
7227
+ "stale_lease",
7228
+ "out_of_order",
7229
+ "not_found"
7230
+ ],
7231
+ "description": "Rejection reason — present only when status is rejected"
7232
+ }
7233
+ }
7234
+ },
7235
+ "AckOutboundMessagesResponse": {
7236
+ "type": "object",
7237
+ "required": [
7238
+ "results"
7239
+ ],
7240
+ "properties": {
7241
+ "results": {
7242
+ "type": "array",
7243
+ "items": {
7244
+ "$ref": "#/components/schemas/AckResult"
7245
+ },
7246
+ "description": "Per-id acknowledgement outcome"
7247
+ }
7248
+ }
7249
+ },
7250
+ "OutboundDlqMessage": {
7251
+ "type": "object",
7252
+ "required": [
7253
+ "id",
7254
+ "use_case_id",
7255
+ "event_name",
7256
+ "event_id",
7257
+ "dead_lettered_at",
7258
+ "delivery_attempts"
7259
+ ],
7260
+ "properties": {
7261
+ "id": {
7262
+ "type": "string",
7263
+ "description": "Opaque message id (msg_…) of the dead-lettered message"
7264
+ },
7265
+ "use_case_id": {
7266
+ "type": "string",
7267
+ "description": "The poll-mode use case that produced this message"
7268
+ },
7269
+ "event_name": {
7270
+ "type": "string",
7271
+ "description": "Standardized event name (e.g. contract.updated)"
7272
+ },
7273
+ "event_id": {
7274
+ "type": "string",
7275
+ "description": "Unique id of the originating event"
7276
+ },
7277
+ "enqueued_at": {
7278
+ "type": "string",
7279
+ "format": "date-time",
7280
+ "description": "When the message was originally enqueued"
7281
+ },
7282
+ "dead_lettered_at": {
7283
+ "type": "string",
7284
+ "format": "date-time",
7285
+ "description": "When the message was dead-lettered"
7286
+ },
7287
+ "delivery_attempts": {
7288
+ "type": "integer",
7289
+ "description": "Delivery attempts at the moment the message was dead-lettered"
7290
+ },
7291
+ "reason": {
7292
+ "type": "string",
7293
+ "description": "Why the message was dead-lettered (policy or operator reason)"
7294
+ },
7295
+ "expires_at": {
7296
+ "type": "string",
7297
+ "format": "date-time",
7298
+ "description": "When the DLQ entry expires (retention window re-armed at dead-letter time)"
7299
+ }
7300
+ }
7301
+ },
7302
+ "OutboundDlqListResponse": {
7303
+ "type": "object",
7304
+ "required": [
7305
+ "items"
7306
+ ],
7307
+ "properties": {
7308
+ "items": {
7309
+ "type": "array",
7310
+ "items": {
7311
+ "$ref": "#/components/schemas/OutboundDlqMessage"
7312
+ },
7313
+ "description": "Dead-lettered messages, oldest first"
7314
+ },
7315
+ "next_token": {
7316
+ "type": "string",
7317
+ "description": "Opaque pagination token — present when more entries exist"
7318
+ }
7319
+ }
7320
+ },
7321
+ "RedriveOutboundDlqRequest": {
7322
+ "type": "object",
7323
+ "additionalProperties": false,
7324
+ "required": [
7325
+ "ids"
7326
+ ],
7327
+ "properties": {
7328
+ "ids": {
7329
+ "type": "array",
7330
+ "minItems": 1,
7331
+ "maxItems": 100,
7332
+ "items": {
7333
+ "type": "string"
7334
+ },
7335
+ "description": "Message ids (msg_…) of the DLQ entries to redrive"
7336
+ }
7337
+ }
7338
+ },
7339
+ "RedriveOutboundDlqResult": {
7340
+ "type": "object",
7341
+ "required": [
7342
+ "id",
7343
+ "status"
7344
+ ],
7345
+ "properties": {
7346
+ "id": {
7347
+ "type": "string",
7348
+ "description": "The requested message id"
7349
+ },
7350
+ "status": {
7351
+ "type": "string",
7352
+ "enum": [
7353
+ "redriven",
7354
+ "not_found"
7355
+ ],
7356
+ "description": "Outcome — `redriven` re-enqueued at the tail; `not_found` for\nunknown ids or entries concurrently redriven/expired\n"
7357
+ }
7358
+ }
7359
+ },
7360
+ "RedriveOutboundDlqResponse": {
7361
+ "type": "object",
7362
+ "required": [
7363
+ "results"
7364
+ ],
7365
+ "properties": {
7366
+ "results": {
7367
+ "type": "array",
7368
+ "items": {
7369
+ "$ref": "#/components/schemas/RedriveOutboundDlqResult"
7370
+ },
7371
+ "description": "Per-id redrive outcome, input order preserved"
7372
+ }
7373
+ }
7374
+ },
7375
+ "UnblockOutboundStreamRequest": {
7376
+ "type": "object",
7377
+ "additionalProperties": false,
7378
+ "properties": {
7379
+ "reason": {
7380
+ "type": "string",
7381
+ "maxLength": 500,
7382
+ "description": "Operator reason recorded on the dead-lettered head"
7383
+ }
7384
+ }
7385
+ },
7386
+ "UnblockOutboundStreamResponse": {
7387
+ "type": "object",
7388
+ "required": [
7389
+ "unblocked"
7390
+ ],
7391
+ "properties": {
7392
+ "unblocked": {
7393
+ "type": "boolean",
7394
+ "description": "Whether a blocked head was skipped (false = no-op, stream was not blocked)"
7395
+ },
7396
+ "dead_lettered_id": {
7397
+ "type": "string",
7398
+ "description": "Message id of the skipped head — present only when unblocked is true"
7399
+ }
7400
+ }
7401
+ },
6653
7402
  "RelationConfig": {
6654
7403
  "type": "object",
6655
7404
  "required": [