@1claw/openapi-spec 0.59.10 → 0.60.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/README.md +21 -1
- package/openapi.json +3306 -349
- package/openapi.yaml +2013 -55
- package/package.json +1 -1
package/openapi.yaml
CHANGED
|
@@ -2,7 +2,7 @@ openapi: 3.1.0
|
|
|
2
2
|
|
|
3
3
|
info:
|
|
4
4
|
title: 1Claw API
|
|
5
|
-
version: "0.
|
|
5
|
+
version: "0.60.0"
|
|
6
6
|
description: |
|
|
7
7
|
Secure secret management for AI agents. Provides vaults, secrets,
|
|
8
8
|
policy-based access control, agent identity, Intents API,
|
|
@@ -836,7 +836,21 @@ paths:
|
|
|
836
836
|
post:
|
|
837
837
|
tags: [Approvals]
|
|
838
838
|
summary: Request human approval (agent-only)
|
|
839
|
-
description:
|
|
839
|
+
description: |
|
|
840
|
+
Ask a human to approve an action.
|
|
841
|
+
|
|
842
|
+
Two families of action are accepted:
|
|
843
|
+
|
|
844
|
+
* the control-plane requests `access_request`, `policy_request`
|
|
845
|
+
and `binding_request`, which widen the agent's own authority; and
|
|
846
|
+
* business actions named `namespace.verb` (`refund.create`,
|
|
847
|
+
`social.post`), whose meaning is carried by `summary` and `payload`.
|
|
848
|
+
|
|
849
|
+
Actions that 1Claw itself executes on approval — `policy_change`,
|
|
850
|
+
`card_order`, `agent_transaction`, `agent_execution`,
|
|
851
|
+
`agent_sign_intent` — are created by the platform and rejected here,
|
|
852
|
+
because the summary a human reads would be agent-supplied while the
|
|
853
|
+
side effect would not be.
|
|
840
854
|
operationId: requestApproval
|
|
841
855
|
requestBody:
|
|
842
856
|
required: true
|
|
@@ -848,20 +862,42 @@ paths:
|
|
|
848
862
|
properties:
|
|
849
863
|
action:
|
|
850
864
|
type: string
|
|
851
|
-
|
|
865
|
+
maxLength: 64
|
|
866
|
+
description: "Control-plane action, or a business action named `namespace.verb`."
|
|
867
|
+
example: refund.create
|
|
852
868
|
target_type:
|
|
853
869
|
type: string
|
|
854
870
|
target_id:
|
|
855
871
|
type: string
|
|
856
872
|
summary:
|
|
857
873
|
type: object
|
|
858
|
-
description: "
|
|
874
|
+
description: "What the human is shown: title, body, and key-value fields."
|
|
875
|
+
example: {title: "Refund $49.99", body: "Order #1234 arrived damaged."}
|
|
876
|
+
payload:
|
|
877
|
+
type: object
|
|
878
|
+
description: |
|
|
879
|
+
What the action will actually do. The enforced risk tier and
|
|
880
|
+
the human-readable line are derived from this, not from
|
|
881
|
+
`summary` — the two can disagree, and only this one describes
|
|
882
|
+
what happens if the human approves.
|
|
883
|
+
example: {amount_usd: "49.99", customer_email: "a.user@example.com"}
|
|
859
884
|
reason:
|
|
860
885
|
type: string
|
|
886
|
+
declared_risk_tier:
|
|
887
|
+
type: integer
|
|
888
|
+
minimum: 1
|
|
889
|
+
maximum: 3
|
|
890
|
+
description: |
|
|
891
|
+
Advisory. The server derives the enforced tier from the agent's
|
|
892
|
+
`action_approval_policy` and the payload, then takes the higher
|
|
893
|
+
of the two: a caller may raise its own bar, never lower it.
|
|
894
|
+
The response returns both.
|
|
861
895
|
risk_tier:
|
|
862
896
|
type: integer
|
|
863
897
|
minimum: 1
|
|
864
|
-
maximum:
|
|
898
|
+
maximum: 3
|
|
899
|
+
deprecated: true
|
|
900
|
+
description: "Former name for `declared_risk_tier`. Still accepted."
|
|
865
901
|
responses:
|
|
866
902
|
"202":
|
|
867
903
|
description: Approval request created
|
|
@@ -6662,6 +6698,224 @@ paths:
|
|
|
6662
6698
|
"404":
|
|
6663
6699
|
$ref: "#/components/responses/NotFound"
|
|
6664
6700
|
|
|
6701
|
+
/v1/platform/apps/{appId}/fleets/{template_id}:
|
|
6702
|
+
get:
|
|
6703
|
+
tags: [Platform]
|
|
6704
|
+
summary: Fleet summary for a template
|
|
6705
|
+
description: >
|
|
6706
|
+
Every agent this template provisioned, as one cohort: how many there are, how
|
|
6707
|
+
they split across the template versions they were built from, and how many a
|
|
6708
|
+
previous rollout declined to touch. plt_ or user JWT.
|
|
6709
|
+
operationId: getFleet
|
|
6710
|
+
security:
|
|
6711
|
+
- BearerAuth: []
|
|
6712
|
+
parameters:
|
|
6713
|
+
- in: path
|
|
6714
|
+
name: appId
|
|
6715
|
+
required: true
|
|
6716
|
+
schema:
|
|
6717
|
+
type: string
|
|
6718
|
+
format: uuid
|
|
6719
|
+
- in: path
|
|
6720
|
+
name: template_id
|
|
6721
|
+
required: true
|
|
6722
|
+
schema:
|
|
6723
|
+
type: string
|
|
6724
|
+
format: uuid
|
|
6725
|
+
responses:
|
|
6726
|
+
"200":
|
|
6727
|
+
description: Fleet summary
|
|
6728
|
+
content:
|
|
6729
|
+
application/json:
|
|
6730
|
+
schema:
|
|
6731
|
+
$ref: "#/components/schemas/FleetSummaryResponse"
|
|
6732
|
+
"404":
|
|
6733
|
+
$ref: "#/components/responses/NotFound"
|
|
6734
|
+
/v1/platform/apps/{appId}/fleets/{template_id}/agents:
|
|
6735
|
+
get:
|
|
6736
|
+
tags: [Platform]
|
|
6737
|
+
summary: List the agents in a fleet
|
|
6738
|
+
operationId: listFleetAgents
|
|
6739
|
+
security:
|
|
6740
|
+
- BearerAuth: []
|
|
6741
|
+
parameters:
|
|
6742
|
+
- in: path
|
|
6743
|
+
name: appId
|
|
6744
|
+
required: true
|
|
6745
|
+
schema:
|
|
6746
|
+
type: string
|
|
6747
|
+
format: uuid
|
|
6748
|
+
- in: path
|
|
6749
|
+
name: template_id
|
|
6750
|
+
required: true
|
|
6751
|
+
schema:
|
|
6752
|
+
type: string
|
|
6753
|
+
format: uuid
|
|
6754
|
+
- in: query
|
|
6755
|
+
name: limit
|
|
6756
|
+
schema:
|
|
6757
|
+
type: integer
|
|
6758
|
+
default: 50
|
|
6759
|
+
minimum: 1
|
|
6760
|
+
maximum: 500
|
|
6761
|
+
- in: query
|
|
6762
|
+
name: offset
|
|
6763
|
+
schema:
|
|
6764
|
+
type: integer
|
|
6765
|
+
default: 0
|
|
6766
|
+
minimum: 0
|
|
6767
|
+
responses:
|
|
6768
|
+
"200":
|
|
6769
|
+
description: Agents in the fleet
|
|
6770
|
+
content:
|
|
6771
|
+
application/json:
|
|
6772
|
+
schema:
|
|
6773
|
+
$ref: "#/components/schemas/ListFleetAgentsResponse"
|
|
6774
|
+
"404":
|
|
6775
|
+
$ref: "#/components/responses/NotFound"
|
|
6776
|
+
/v1/platform/apps/{appId}/fleets/{template_id}/bulk-patch:
|
|
6777
|
+
post:
|
|
6778
|
+
tags: [Platform]
|
|
6779
|
+
summary: Patch every agent in a fleet
|
|
6780
|
+
description: >
|
|
6781
|
+
Applies one patch to every agent in the cohort. The field allowlist is
|
|
6782
|
+
deliberately narrower than a single-agent PATCH: guardrails and capability
|
|
6783
|
+
flags (intents_api_enabled, execution_intents_enabled) cannot be changed here,
|
|
6784
|
+
because at cohort scale nobody reviews the change per agent. Read the
|
|
6785
|
+
allowlist from bulk_patchable_fields on the fleet summary rather than hard-coding
|
|
6786
|
+
it. A field outside it returns 400 naming the field.
|
|
6787
|
+
operationId: bulkPatchFleet
|
|
6788
|
+
security:
|
|
6789
|
+
- BearerAuth: []
|
|
6790
|
+
parameters:
|
|
6791
|
+
- in: path
|
|
6792
|
+
name: appId
|
|
6793
|
+
required: true
|
|
6794
|
+
schema:
|
|
6795
|
+
type: string
|
|
6796
|
+
format: uuid
|
|
6797
|
+
- in: path
|
|
6798
|
+
name: template_id
|
|
6799
|
+
required: true
|
|
6800
|
+
schema:
|
|
6801
|
+
type: string
|
|
6802
|
+
format: uuid
|
|
6803
|
+
requestBody:
|
|
6804
|
+
required: true
|
|
6805
|
+
content:
|
|
6806
|
+
application/json:
|
|
6807
|
+
schema:
|
|
6808
|
+
type: object
|
|
6809
|
+
required: [patch]
|
|
6810
|
+
properties:
|
|
6811
|
+
patch:
|
|
6812
|
+
type: object
|
|
6813
|
+
additionalProperties: true
|
|
6814
|
+
description: Fields to set on every agent in the cohort.
|
|
6815
|
+
responses:
|
|
6816
|
+
"200":
|
|
6817
|
+
description: Patch applied
|
|
6818
|
+
content:
|
|
6819
|
+
application/json:
|
|
6820
|
+
schema:
|
|
6821
|
+
type: object
|
|
6822
|
+
properties:
|
|
6823
|
+
fields_applied:
|
|
6824
|
+
type: array
|
|
6825
|
+
items: { type: string }
|
|
6826
|
+
agents_matched: { type: integer, format: int64 }
|
|
6827
|
+
agents_updated: { type: integer, format: int64 }
|
|
6828
|
+
"400":
|
|
6829
|
+
description: A field outside the bulk-patch allowlist, or an empty patch
|
|
6830
|
+
"404":
|
|
6831
|
+
$ref: "#/components/responses/NotFound"
|
|
6832
|
+
/v1/platform/apps/{appId}/fleets/{template_id}/rollout:
|
|
6833
|
+
post:
|
|
6834
|
+
tags: [Platform]
|
|
6835
|
+
summary: Roll the current template version out to its fleet
|
|
6836
|
+
description: >
|
|
6837
|
+
Brings every agent in the cohort up to the template's current version. An agent
|
|
6838
|
+
changed outside fleet control is skipped rather than corrected, and the fields
|
|
6839
|
+
that caused the skip are recorded on it. force=true overrides that skip but
|
|
6840
|
+
still cannot carry a guardrail or a capability flag. dry_run=true reports what
|
|
6841
|
+
would happen and claims nothing, so it never blocks a real rollout. Only one
|
|
6842
|
+
rollout may run per template at a time; a second returns 409.
|
|
6843
|
+
operationId: rolloutFleet
|
|
6844
|
+
security:
|
|
6845
|
+
- BearerAuth: []
|
|
6846
|
+
parameters:
|
|
6847
|
+
- in: path
|
|
6848
|
+
name: appId
|
|
6849
|
+
required: true
|
|
6850
|
+
schema:
|
|
6851
|
+
type: string
|
|
6852
|
+
format: uuid
|
|
6853
|
+
- in: path
|
|
6854
|
+
name: template_id
|
|
6855
|
+
required: true
|
|
6856
|
+
schema:
|
|
6857
|
+
type: string
|
|
6858
|
+
format: uuid
|
|
6859
|
+
requestBody:
|
|
6860
|
+
required: false
|
|
6861
|
+
content:
|
|
6862
|
+
application/json:
|
|
6863
|
+
schema:
|
|
6864
|
+
type: object
|
|
6865
|
+
properties:
|
|
6866
|
+
force:
|
|
6867
|
+
type: boolean
|
|
6868
|
+
default: false
|
|
6869
|
+
description: Overwrite hand edits. Cannot carry guardrails.
|
|
6870
|
+
dry_run:
|
|
6871
|
+
type: boolean
|
|
6872
|
+
default: false
|
|
6873
|
+
description: Report the plan without applying it.
|
|
6874
|
+
responses:
|
|
6875
|
+
"200":
|
|
6876
|
+
description: Rollout result
|
|
6877
|
+
content:
|
|
6878
|
+
application/json:
|
|
6879
|
+
schema:
|
|
6880
|
+
$ref: "#/components/schemas/FleetRolloutResponse"
|
|
6881
|
+
"409":
|
|
6882
|
+
description: A rollout is already running for this template
|
|
6883
|
+
"404":
|
|
6884
|
+
$ref: "#/components/responses/NotFound"
|
|
6885
|
+
/v1/platform/apps/{appId}/fleets/{template_id}/pause:
|
|
6886
|
+
post:
|
|
6887
|
+
tags: [Platform]
|
|
6888
|
+
summary: Deactivate every agent in a fleet
|
|
6889
|
+
description: >
|
|
6890
|
+
Sets is_active=false on the whole cohort. The blast radius is the point: this
|
|
6891
|
+
exists for the moment an operator needs a thousand agents to stop at once.
|
|
6892
|
+
operationId: pauseFleet
|
|
6893
|
+
security:
|
|
6894
|
+
- BearerAuth: []
|
|
6895
|
+
parameters:
|
|
6896
|
+
- in: path
|
|
6897
|
+
name: appId
|
|
6898
|
+
required: true
|
|
6899
|
+
schema:
|
|
6900
|
+
type: string
|
|
6901
|
+
format: uuid
|
|
6902
|
+
- in: path
|
|
6903
|
+
name: template_id
|
|
6904
|
+
required: true
|
|
6905
|
+
schema:
|
|
6906
|
+
type: string
|
|
6907
|
+
format: uuid
|
|
6908
|
+
responses:
|
|
6909
|
+
"200":
|
|
6910
|
+
description: Agents paused
|
|
6911
|
+
content:
|
|
6912
|
+
application/json:
|
|
6913
|
+
schema:
|
|
6914
|
+
type: object
|
|
6915
|
+
properties:
|
|
6916
|
+
agents_paused: { type: integer, format: int64 }
|
|
6917
|
+
"404":
|
|
6918
|
+
$ref: "#/components/responses/NotFound"
|
|
6665
6919
|
/v1/platform/apps/{appId}/templates/{template_id}/preview:
|
|
6666
6920
|
post:
|
|
6667
6921
|
tags: [Platform]
|
|
@@ -11345,85 +11599,1409 @@ paths:
|
|
|
11345
11599
|
"200":
|
|
11346
11600
|
description: Webhook processed
|
|
11347
11601
|
|
|
11348
|
-
/v1/
|
|
11349
|
-
|
|
11350
|
-
tags: [
|
|
11351
|
-
summary:
|
|
11352
|
-
description:
|
|
11353
|
-
|
|
11354
|
-
|
|
11602
|
+
/v1/platform/apps/{app_id}/usage:
|
|
11603
|
+
get:
|
|
11604
|
+
tags: [Platform API]
|
|
11605
|
+
summary: Usage for every connection on an app
|
|
11606
|
+
description: |
|
|
11607
|
+
Billable activity for the current month, grouped by end-user connection,
|
|
11608
|
+
**plus what could not be charged to one**.
|
|
11609
|
+
|
|
11610
|
+
The `unattributed` block is not an implementation detail. Summing only the
|
|
11611
|
+
per-connection numbers gives a figure that will not match the invoice you
|
|
11612
|
+
are reconciling against, and the gap is usage that belongs to a real
|
|
11613
|
+
end-user we cannot name.
|
|
11614
|
+
|
|
11615
|
+
Two kinds, deliberately kept apart:
|
|
11616
|
+
|
|
11617
|
+
* `none` — no platform linkage at all. Normal for most traffic, not a problem.
|
|
11618
|
+
* `ambiguous` — the agent belongs to several connections and no
|
|
11619
|
+
`X-Platform-Connection` header said which. This usage belongs to
|
|
11620
|
+
*someone*. `has_ambiguous_usage` flags it so you do not have to notice
|
|
11621
|
+
a non-zero nested number.
|
|
11622
|
+
|
|
11623
|
+
`totals` is derived from the parts, never queried separately, so it cannot
|
|
11624
|
+
disagree with its own breakdown.
|
|
11625
|
+
operationId: getAppUsage
|
|
11355
11626
|
parameters:
|
|
11356
|
-
- name:
|
|
11627
|
+
- name: app_id
|
|
11357
11628
|
in: path
|
|
11358
11629
|
required: true
|
|
11359
|
-
schema:
|
|
11360
|
-
type: string
|
|
11361
|
-
requestBody:
|
|
11362
|
-
required: true
|
|
11363
|
-
content:
|
|
11364
|
-
application/json:
|
|
11365
|
-
schema:
|
|
11366
|
-
type: object
|
|
11630
|
+
schema: { type: string, format: uuid }
|
|
11367
11631
|
responses:
|
|
11368
11632
|
"200":
|
|
11369
|
-
description:
|
|
11370
|
-
|
|
11371
|
-
|
|
11372
|
-
|
|
11373
|
-
|
|
11633
|
+
description: Usage report
|
|
11634
|
+
content:
|
|
11635
|
+
application/json:
|
|
11636
|
+
schema:
|
|
11637
|
+
$ref: "#/components/schemas/AppUsageReport"
|
|
11638
|
+
"404":
|
|
11639
|
+
$ref: "#/components/responses/NotFound"
|
|
11374
11640
|
|
|
11375
|
-
/v1/
|
|
11641
|
+
/v1/platform/apps/{app_id}/usage/export:
|
|
11376
11642
|
get:
|
|
11377
|
-
tags: [
|
|
11378
|
-
summary:
|
|
11643
|
+
tags: [Platform API]
|
|
11644
|
+
summary: Usage as CSV for billing reconciliation
|
|
11379
11645
|
description: |
|
|
11380
|
-
|
|
11381
|
-
|
|
11382
|
-
|
|
11383
|
-
|
|
11646
|
+
The same report as `GET /usage`, as CSV. Includes the `ambiguous`, `none`
|
|
11647
|
+
and `total` rows — a CSV listing only connections looks complete and is
|
|
11648
|
+
not, and whoever imports it has no way to tell.
|
|
11649
|
+
operationId: exportAppUsage
|
|
11650
|
+
parameters:
|
|
11651
|
+
- name: app_id
|
|
11652
|
+
in: path
|
|
11653
|
+
required: true
|
|
11654
|
+
schema: { type: string, format: uuid }
|
|
11384
11655
|
responses:
|
|
11385
11656
|
"200":
|
|
11386
|
-
description:
|
|
11657
|
+
description: CSV
|
|
11387
11658
|
content:
|
|
11388
|
-
|
|
11389
|
-
schema:
|
|
11390
|
-
|
|
11659
|
+
text/csv:
|
|
11660
|
+
schema: { type: string }
|
|
11661
|
+
"404":
|
|
11662
|
+
$ref: "#/components/responses/NotFound"
|
|
11391
11663
|
|
|
11392
|
-
/v1/
|
|
11664
|
+
/v1/org/apply:
|
|
11393
11665
|
post:
|
|
11394
|
-
tags: [
|
|
11395
|
-
summary:
|
|
11666
|
+
tags: [Organization]
|
|
11667
|
+
summary: Apply a chart
|
|
11396
11668
|
description: |
|
|
11397
|
-
|
|
11398
|
-
|
|
11399
|
-
|
|
11400
|
-
|
|
11401
|
-
-
|
|
11669
|
+
Create what the chart describes. Human users only.
|
|
11670
|
+
|
|
11671
|
+
**Apply calls the same handlers the HTTP routes call.** Creating a vault
|
|
11672
|
+
runs five gates before anything is written — the delegation scope, a name
|
|
11673
|
+
check, control-plane consensus, a creation rate limit and the tier quota
|
|
11674
|
+
— and creating an agent runs its own. A reconciler that wrote through the
|
|
11675
|
+
repositories would skip all of them and would look, in review, exactly
|
|
11676
|
+
like one that did not.
|
|
11677
|
+
|
|
11678
|
+
So if your org has consensus configured on `vault.create`, applying a
|
|
11679
|
+
chart queues an approval exactly as a dashboard click would. That resource
|
|
11680
|
+
comes back as `awaiting_approval` rather than failing the whole chart.
|
|
11681
|
+
|
|
11682
|
+
Per-resource results: `created`, `unchanged`, `skipped`, `refused`,
|
|
11683
|
+
`awaiting_approval`, `failed`. `needs_attention` is true when the chart is
|
|
11684
|
+
not fully applied — something is waiting on a person, whether an approval,
|
|
11685
|
+
an OAuth sign-in, or a resource that drifted and was left alone.
|
|
11686
|
+
|
|
11687
|
+
Save `applied_state` to `.1claw/apply-state.json`. It records what apply
|
|
11688
|
+
set, which is what lets the next run tell drift from a first apply.
|
|
11689
|
+
|
|
11690
|
+
v1 creates and reports; it does not delete, prune, or patch in place. An
|
|
11691
|
+
apply that silently deletes is an apply nobody runs twice.
|
|
11692
|
+
operationId: applyChart
|
|
11402
11693
|
requestBody:
|
|
11403
11694
|
required: true
|
|
11404
11695
|
content:
|
|
11405
11696
|
application/json:
|
|
11406
11697
|
schema:
|
|
11407
|
-
|
|
11698
|
+
type: object
|
|
11699
|
+
required: [chart]
|
|
11700
|
+
properties:
|
|
11701
|
+
chart:
|
|
11702
|
+
type: object
|
|
11703
|
+
description: A chart document — `apiVersion`, `kind`, `metadata`, `spec`.
|
|
11704
|
+
applied_state:
|
|
11705
|
+
type: object
|
|
11706
|
+
additionalProperties: true
|
|
11408
11707
|
responses:
|
|
11409
11708
|
"200":
|
|
11410
|
-
description:
|
|
11709
|
+
description: What happened to each resource
|
|
11411
11710
|
content:
|
|
11412
11711
|
application/json:
|
|
11413
11712
|
schema:
|
|
11414
|
-
|
|
11713
|
+
type: object
|
|
11714
|
+
properties:
|
|
11715
|
+
chart_name: { type: string }
|
|
11716
|
+
resources:
|
|
11717
|
+
type: array
|
|
11718
|
+
items:
|
|
11719
|
+
type: object
|
|
11720
|
+
properties:
|
|
11721
|
+
kind: { type: string }
|
|
11722
|
+
name: { type: string }
|
|
11723
|
+
result:
|
|
11724
|
+
type: string
|
|
11725
|
+
enum: [created, unchanged, skipped, refused, awaiting_approval, failed]
|
|
11726
|
+
id: { type: string, format: uuid }
|
|
11727
|
+
detail: { type: string }
|
|
11728
|
+
warnings:
|
|
11729
|
+
type: array
|
|
11730
|
+
items: { type: string }
|
|
11731
|
+
applied_state:
|
|
11732
|
+
type: object
|
|
11733
|
+
additionalProperties: true
|
|
11734
|
+
description: Save to `.1claw/apply-state.json`.
|
|
11735
|
+
needs_attention:
|
|
11736
|
+
type: boolean
|
|
11737
|
+
description: The chart is not fully applied — something is waiting on a person.
|
|
11415
11738
|
"400":
|
|
11416
11739
|
$ref: "#/components/responses/BadRequest"
|
|
11417
11740
|
"403":
|
|
11418
11741
|
$ref: "#/components/responses/Forbidden"
|
|
11419
|
-
"404":
|
|
11420
|
-
$ref: "#/components/responses/NotFound"
|
|
11421
11742
|
|
|
11422
|
-
/v1/
|
|
11743
|
+
/v1/org/approval-learning/shadow-report:
|
|
11423
11744
|
get:
|
|
11424
|
-
tags: [
|
|
11425
|
-
summary:
|
|
11426
|
-
description:
|
|
11745
|
+
tags: [Organization]
|
|
11746
|
+
summary: What would have been approved automatically
|
|
11747
|
+
description: |
|
|
11748
|
+
Every approval decision is observed, per **fingerprint bucket** — the
|
|
11749
|
+
action, the amount band, whether the recipient was new, and who they
|
|
11750
|
+
were. This reports the buckets a person has approved without exception,
|
|
11751
|
+
and what promoting one would write into an agent's policy.
|
|
11752
|
+
|
|
11753
|
+
Observing is not acting. In the default `shadow` mode nothing changes who
|
|
11754
|
+
gets asked; `can_promote` is false and the promote endpoint refuses.
|
|
11755
|
+
|
|
11756
|
+
Each suggestion carries `would_write_rule` — the actual rule, built by the
|
|
11757
|
+
same function promotion uses, so the report cannot promise something
|
|
11758
|
+
promotion would refuse.
|
|
11759
|
+
operationId: getApprovalLearningShadowReport
|
|
11760
|
+
responses:
|
|
11761
|
+
"200":
|
|
11762
|
+
description: Report
|
|
11763
|
+
content:
|
|
11764
|
+
application/json:
|
|
11765
|
+
schema:
|
|
11766
|
+
type: object
|
|
11767
|
+
properties:
|
|
11768
|
+
mode: { type: string, enum: [shadow, enforce] }
|
|
11769
|
+
threshold:
|
|
11770
|
+
type: integer
|
|
11771
|
+
description: Consecutive approvals in one bucket before it appears here.
|
|
11772
|
+
can_promote: { type: boolean }
|
|
11773
|
+
observed_buckets: { type: integer }
|
|
11774
|
+
total_decisions: { type: integer }
|
|
11775
|
+
suggestions:
|
|
11776
|
+
type: array
|
|
11777
|
+
items:
|
|
11778
|
+
type: object
|
|
11779
|
+
properties:
|
|
11780
|
+
profile_id: { type: string, format: uuid }
|
|
11781
|
+
action_type: { type: string }
|
|
11782
|
+
fingerprint_bucket: { type: string, example: "refund.create|0-10|known|a@b.co" }
|
|
11783
|
+
consecutive_approvals: { type: integer }
|
|
11784
|
+
total_requests: { type: integer }
|
|
11785
|
+
would_write_rule: { type: object, nullable: true }
|
|
11786
|
+
blocked:
|
|
11787
|
+
type: string
|
|
11788
|
+
description: Present when a bound prevents promotion, saying which.
|
|
11789
|
+
last_decision_at: { type: string, format: date-time }
|
|
11790
|
+
"403":
|
|
11791
|
+
$ref: "#/components/responses/Forbidden"
|
|
11792
|
+
|
|
11793
|
+
/v1/org/approval-learning/{profile_id}/promote:
|
|
11794
|
+
post:
|
|
11795
|
+
tags: [Organization]
|
|
11796
|
+
summary: Turn an observed pattern into a policy rule
|
|
11797
|
+
description: |
|
|
11798
|
+
Writes a rule into the named agent's `action_approval_policy`. Human users
|
|
11799
|
+
only, and only when the organisation is in `enforce` mode.
|
|
11800
|
+
|
|
11801
|
+
**The rule covers only what was actually approved.** Five approved $5
|
|
11802
|
+
refunds to one customer produce `{ refund.create, asks above $10, that
|
|
11803
|
+
recipient }` — a $49 request does not match it and still reaches a human.
|
|
11804
|
+
|
|
11805
|
+
Refused when: fewer than five consecutive approvals; *any* past rejection
|
|
11806
|
+
on the bucket (a long recent run must not hide a history of refusals); the
|
|
11807
|
+
bucket is for a recipient never paid before; the amount band has no upper
|
|
11808
|
+
edge; or the action grants or destroys authority.
|
|
11809
|
+
|
|
11810
|
+
`widen_to_action_type` drops the amount and recipient constraints. It is
|
|
11811
|
+
never the default and should be an explicit choice in your UI, not a
|
|
11812
|
+
checkbox someone skims past.
|
|
11813
|
+
|
|
11814
|
+
The written rule is marked `promoted_from_learning` so an operator can
|
|
11815
|
+
tell it apart from one they wrote, and it replaces any existing rule for
|
|
11816
|
+
the same action type — appending would leave two rules where only the
|
|
11817
|
+
first ever applies.
|
|
11818
|
+
operationId: promoteApprovalLearningProfile
|
|
11819
|
+
parameters:
|
|
11820
|
+
- name: profile_id
|
|
11821
|
+
in: path
|
|
11822
|
+
required: true
|
|
11823
|
+
schema: { type: string, format: uuid }
|
|
11824
|
+
requestBody:
|
|
11825
|
+
required: true
|
|
11826
|
+
content:
|
|
11827
|
+
application/json:
|
|
11828
|
+
schema:
|
|
11829
|
+
type: object
|
|
11830
|
+
required: [agent_id]
|
|
11831
|
+
properties:
|
|
11832
|
+
agent_id: { type: string, format: uuid }
|
|
11833
|
+
widen_to_action_type:
|
|
11834
|
+
type: boolean
|
|
11835
|
+
default: false
|
|
11836
|
+
responses:
|
|
11837
|
+
"200":
|
|
11838
|
+
description: Promoted
|
|
11839
|
+
content:
|
|
11840
|
+
application/json:
|
|
11841
|
+
schema:
|
|
11842
|
+
type: object
|
|
11843
|
+
properties:
|
|
11844
|
+
profile_id: { type: string, format: uuid }
|
|
11845
|
+
agent_id: { type: string, format: uuid }
|
|
11846
|
+
rule: { type: object }
|
|
11847
|
+
"400":
|
|
11848
|
+
$ref: "#/components/responses/BadRequest"
|
|
11849
|
+
"403":
|
|
11850
|
+
$ref: "#/components/responses/Forbidden"
|
|
11851
|
+
"404":
|
|
11852
|
+
$ref: "#/components/responses/NotFound"
|
|
11853
|
+
"409":
|
|
11854
|
+
$ref: "#/components/responses/Conflict"
|
|
11855
|
+
|
|
11856
|
+
/v1/policy-presets:
|
|
11857
|
+
get:
|
|
11858
|
+
tags: [Policies]
|
|
11859
|
+
summary: Named starting points for an agent's policy
|
|
11860
|
+
description: |
|
|
11861
|
+
Four presets an operator can choose between without reading a policy
|
|
11862
|
+
document. Public — a description of what 1Claw offers, not tenant data.
|
|
11863
|
+
|
|
11864
|
+
Each carries a `headline`: the one-line consequence someone should read
|
|
11865
|
+
before choosing it, in the words they would use.
|
|
11866
|
+
operationId: listPolicyPresets
|
|
11867
|
+
security: []
|
|
11868
|
+
responses:
|
|
11869
|
+
"200":
|
|
11870
|
+
description: Catalogue
|
|
11871
|
+
content:
|
|
11872
|
+
application/json:
|
|
11873
|
+
schema:
|
|
11874
|
+
type: object
|
|
11875
|
+
properties:
|
|
11876
|
+
presets: { type: array, items: { type: object } }
|
|
11877
|
+
|
|
11878
|
+
/v1/agents/{agent_id}/policy-preset/preview:
|
|
11879
|
+
post:
|
|
11880
|
+
tags: [Policies]
|
|
11881
|
+
summary: What a preset would change
|
|
11882
|
+
description: |
|
|
11883
|
+
Compiles a preset against this agent and reports which fields it would
|
|
11884
|
+
**widen** — loosen relative to what the agent can already do.
|
|
11885
|
+
|
|
11886
|
+
Widening detection errs toward flagging: a false positive costs one extra
|
|
11887
|
+
approval, a false negative is a limit raised without review. Enabling a
|
|
11888
|
+
capability widens; disabling does not. Raising a cap widens; setting a
|
|
11889
|
+
first cap does not, because absent means unlimited.
|
|
11890
|
+
operationId: previewPolicyPreset
|
|
11891
|
+
parameters:
|
|
11892
|
+
- name: agent_id
|
|
11893
|
+
in: path
|
|
11894
|
+
required: true
|
|
11895
|
+
schema: { type: string, format: uuid }
|
|
11896
|
+
requestBody:
|
|
11897
|
+
required: true
|
|
11898
|
+
content:
|
|
11899
|
+
application/json:
|
|
11900
|
+
schema:
|
|
11901
|
+
type: object
|
|
11902
|
+
required: [preset]
|
|
11903
|
+
properties:
|
|
11904
|
+
preset: { type: string, example: small-business-spender }
|
|
11905
|
+
responses:
|
|
11906
|
+
"200":
|
|
11907
|
+
description: Proposal
|
|
11908
|
+
content:
|
|
11909
|
+
application/json:
|
|
11910
|
+
schema:
|
|
11911
|
+
type: object
|
|
11912
|
+
properties:
|
|
11913
|
+
preset_slug: { type: string }
|
|
11914
|
+
guardrails: { type: object }
|
|
11915
|
+
action_approval_policy: { type: object }
|
|
11916
|
+
access_policy: { type: object }
|
|
11917
|
+
widens:
|
|
11918
|
+
type: array
|
|
11919
|
+
items: { type: string }
|
|
11920
|
+
description: Fields this preset would loosen. Show these, not a generic warning.
|
|
11921
|
+
requires_guardrail_approval: { type: boolean }
|
|
11922
|
+
explanation: { type: string }
|
|
11923
|
+
"403":
|
|
11924
|
+
$ref: "#/components/responses/Forbidden"
|
|
11925
|
+
"404":
|
|
11926
|
+
$ref: "#/components/responses/NotFound"
|
|
11927
|
+
|
|
11928
|
+
/v1/agents/{agent_id}/policy-preset:
|
|
11929
|
+
post:
|
|
11930
|
+
tags: [Policies]
|
|
11931
|
+
summary: Apply a policy preset
|
|
11932
|
+
description: |
|
|
11933
|
+
**Applies through the agent update handler**, not by writing guardrail
|
|
11934
|
+
columns. A preset that wrote them directly would be a way around the
|
|
11935
|
+
guardrail widening approval flow wearing a friendlier interface.
|
|
11936
|
+
|
|
11937
|
+
So if the preset loosens something and your organisation gates that, you
|
|
11938
|
+
get the same **202 with a pending approval** you would get from editing
|
|
11939
|
+
the agent by hand — not a quietly applied change. Pass `approval_id`
|
|
11940
|
+
once that approval is granted.
|
|
11941
|
+
operationId: applyPolicyPreset
|
|
11942
|
+
parameters:
|
|
11943
|
+
- name: agent_id
|
|
11944
|
+
in: path
|
|
11945
|
+
required: true
|
|
11946
|
+
schema: { type: string, format: uuid }
|
|
11947
|
+
requestBody:
|
|
11948
|
+
required: true
|
|
11949
|
+
content:
|
|
11950
|
+
application/json:
|
|
11951
|
+
schema:
|
|
11952
|
+
type: object
|
|
11953
|
+
required: [preset]
|
|
11954
|
+
properties:
|
|
11955
|
+
preset: { type: string }
|
|
11956
|
+
approval_id: { type: string, format: uuid }
|
|
11957
|
+
responses:
|
|
11958
|
+
"200":
|
|
11959
|
+
description: Applied
|
|
11960
|
+
"202":
|
|
11961
|
+
description: Queued behind a guardrail approval
|
|
11962
|
+
"403":
|
|
11963
|
+
$ref: "#/components/responses/Forbidden"
|
|
11964
|
+
"404":
|
|
11965
|
+
$ref: "#/components/responses/NotFound"
|
|
11966
|
+
|
|
11967
|
+
/v1/agents/{agent_id}/trust:
|
|
11968
|
+
get:
|
|
11969
|
+
tags: [Discovery]
|
|
11970
|
+
summary: What a listed agent has earned
|
|
11971
|
+
description: |
|
|
11972
|
+
Everything a publisher writes — name, description, tags — is a claim.
|
|
11973
|
+
These are the parts they cannot write: whether a human reviewed the
|
|
11974
|
+
listing, how many people installed it, what they rated it.
|
|
11975
|
+
|
|
11976
|
+
Public, because its purpose is to be read by someone deciding whether to
|
|
11977
|
+
install a stranger's agent. Only listed agents have public trust.
|
|
11978
|
+
|
|
11979
|
+
**A listing with reports shows no badges at all.** "Platform reviewed"
|
|
11980
|
+
beside an active complaint tells a reader the opposite of what they need.
|
|
11981
|
+
An average rating appears only from three reviews — one rating is not an
|
|
11982
|
+
average.
|
|
11983
|
+
operationId: getAgentTrust
|
|
11984
|
+
security: []
|
|
11985
|
+
parameters:
|
|
11986
|
+
- name: agent_id
|
|
11987
|
+
in: path
|
|
11988
|
+
required: true
|
|
11989
|
+
schema: { type: string, format: uuid }
|
|
11990
|
+
responses:
|
|
11991
|
+
"200":
|
|
11992
|
+
description: Trust signals
|
|
11993
|
+
content:
|
|
11994
|
+
application/json:
|
|
11995
|
+
schema:
|
|
11996
|
+
type: object
|
|
11997
|
+
properties:
|
|
11998
|
+
trust:
|
|
11999
|
+
type: object
|
|
12000
|
+
properties:
|
|
12001
|
+
tier: { type: string, enum: [unverified, platform_reviewed, identity_verified, enterprise] }
|
|
12002
|
+
install_count: { type: integer }
|
|
12003
|
+
avg_rating: { type: number, nullable: true }
|
|
12004
|
+
review_count: { type: integer }
|
|
12005
|
+
badges: { type: array, items: { type: string } }
|
|
12006
|
+
flagged_for_review: { type: boolean }
|
|
12007
|
+
"404":
|
|
12008
|
+
$ref: "#/components/responses/NotFound"
|
|
12009
|
+
|
|
12010
|
+
/v1/agents/{agent_id}/report:
|
|
12011
|
+
post:
|
|
12012
|
+
tags: [Discovery]
|
|
12013
|
+
summary: Report a listed agent
|
|
12014
|
+
description: |
|
|
12015
|
+
Human users only — an agent reporting another agent is a way to bury a
|
|
12016
|
+
competitor's listing at machine speed.
|
|
12017
|
+
|
|
12018
|
+
The response does not include the report count. Telling a reporter how
|
|
12019
|
+
close a listing is to being flagged tells them how many more to file.
|
|
12020
|
+
operationId: reportAgent
|
|
12021
|
+
parameters:
|
|
12022
|
+
- name: agent_id
|
|
12023
|
+
in: path
|
|
12024
|
+
required: true
|
|
12025
|
+
schema: { type: string, format: uuid }
|
|
12026
|
+
requestBody:
|
|
12027
|
+
required: true
|
|
12028
|
+
content:
|
|
12029
|
+
application/json:
|
|
12030
|
+
schema:
|
|
12031
|
+
type: object
|
|
12032
|
+
properties:
|
|
12033
|
+
reason: { type: string }
|
|
12034
|
+
responses:
|
|
12035
|
+
"202":
|
|
12036
|
+
description: Received
|
|
12037
|
+
"403":
|
|
12038
|
+
$ref: "#/components/responses/Forbidden"
|
|
12039
|
+
"404":
|
|
12040
|
+
$ref: "#/components/responses/NotFound"
|
|
12041
|
+
|
|
12042
|
+
/v1/agents/{agent_id}/review:
|
|
12043
|
+
post:
|
|
12044
|
+
tags: [Discovery]
|
|
12045
|
+
summary: Rate an agent you have used
|
|
12046
|
+
description: |
|
|
12047
|
+
One review per person per agent; a second replaces the first. You cannot
|
|
12048
|
+
review an agent from your own organisation.
|
|
12049
|
+
|
|
12050
|
+
Comments are shown only once moderated. The rating counts either way — a
|
|
12051
|
+
number is harder to abuse than free text.
|
|
12052
|
+
operationId: reviewAgent
|
|
12053
|
+
parameters:
|
|
12054
|
+
- name: agent_id
|
|
12055
|
+
in: path
|
|
12056
|
+
required: true
|
|
12057
|
+
schema: { type: string, format: uuid }
|
|
12058
|
+
requestBody:
|
|
12059
|
+
required: true
|
|
12060
|
+
content:
|
|
12061
|
+
application/json:
|
|
12062
|
+
schema:
|
|
12063
|
+
type: object
|
|
12064
|
+
required: [rating]
|
|
12065
|
+
properties:
|
|
12066
|
+
rating: { type: integer, minimum: 1, maximum: 5 }
|
|
12067
|
+
comment: { type: string }
|
|
12068
|
+
responses:
|
|
12069
|
+
"201":
|
|
12070
|
+
description: Recorded
|
|
12071
|
+
"400":
|
|
12072
|
+
$ref: "#/components/responses/BadRequest"
|
|
12073
|
+
"403":
|
|
12074
|
+
$ref: "#/components/responses/Forbidden"
|
|
12075
|
+
"404":
|
|
12076
|
+
$ref: "#/components/responses/NotFound"
|
|
12077
|
+
|
|
12078
|
+
/v1/peers:
|
|
12079
|
+
post:
|
|
12080
|
+
tags: [Memory]
|
|
12081
|
+
summary: Create a peer and name its observers
|
|
12082
|
+
description: |
|
|
12083
|
+
Human users only. Creating a peer decides which agents may read a model
|
|
12084
|
+
of a person, and an agent that could do that could add itself.
|
|
12085
|
+
|
|
12086
|
+
Idempotent on `(org, peer_type, peer_ref)`. Observers are **merged**, not
|
|
12087
|
+
replaced — a second call adding one agent does not revoke the others
|
|
12088
|
+
already watching. Every named observer must be an agent in this
|
|
12089
|
+
organisation, so a typo or an id copied from elsewhere is an error rather
|
|
12090
|
+
than a silent no-op that leaves an operator believing an agent is
|
|
12091
|
+
watching when none is.
|
|
12092
|
+
operationId: createPeer
|
|
12093
|
+
requestBody:
|
|
12094
|
+
required: true
|
|
12095
|
+
content:
|
|
12096
|
+
application/json:
|
|
12097
|
+
schema:
|
|
12098
|
+
type: object
|
|
12099
|
+
required: [peer_type, peer_ref]
|
|
12100
|
+
properties:
|
|
12101
|
+
peer_type: { type: string, enum: [user, platform_connection, external] }
|
|
12102
|
+
peer_ref: { type: string }
|
|
12103
|
+
display_name: { type: string }
|
|
12104
|
+
platform_connection_id: { type: string, format: uuid }
|
|
12105
|
+
observer_agent_ids:
|
|
12106
|
+
type: array
|
|
12107
|
+
items: { type: string, format: uuid }
|
|
12108
|
+
description: Empty means nobody. A peer with no observers is readable by no agent.
|
|
12109
|
+
responses:
|
|
12110
|
+
"201":
|
|
12111
|
+
description: Peer created or updated
|
|
12112
|
+
content:
|
|
12113
|
+
application/json:
|
|
12114
|
+
schema:
|
|
12115
|
+
type: object
|
|
12116
|
+
properties:
|
|
12117
|
+
peer: { $ref: "#/components/schemas/Peer" }
|
|
12118
|
+
"400":
|
|
12119
|
+
$ref: "#/components/responses/BadRequest"
|
|
12120
|
+
"403":
|
|
12121
|
+
$ref: "#/components/responses/Forbidden"
|
|
12122
|
+
|
|
12123
|
+
/v1/peers/{peer_id}/export:
|
|
12124
|
+
get:
|
|
12125
|
+
tags: [Memory]
|
|
12126
|
+
summary: Everything held about this person
|
|
12127
|
+
description: |
|
|
12128
|
+
The whole behavioural profile plus the raw observations behind it. Human
|
|
12129
|
+
users only, behind strong-factor re-auth — this is exactly what a stolen
|
|
12130
|
+
session would want.
|
|
12131
|
+
|
|
12132
|
+
Each fact carries `why_we_believe_this`: its provenance, including
|
|
12133
|
+
tombstones for observations that have since expired. An export listing
|
|
12134
|
+
conclusions without their basis answers only the easy half of the
|
|
12135
|
+
question.
|
|
12136
|
+
operationId: exportPeerData
|
|
12137
|
+
parameters:
|
|
12138
|
+
- name: peer_id
|
|
12139
|
+
in: path
|
|
12140
|
+
required: true
|
|
12141
|
+
schema: { type: string, format: uuid }
|
|
12142
|
+
responses:
|
|
12143
|
+
"200":
|
|
12144
|
+
description: Export
|
|
12145
|
+
content:
|
|
12146
|
+
application/json:
|
|
12147
|
+
schema:
|
|
12148
|
+
type: object
|
|
12149
|
+
properties:
|
|
12150
|
+
peer: { type: object }
|
|
12151
|
+
facts:
|
|
12152
|
+
type: array
|
|
12153
|
+
items:
|
|
12154
|
+
type: object
|
|
12155
|
+
properties:
|
|
12156
|
+
fact_key: { type: string }
|
|
12157
|
+
fact_value: { type: object }
|
|
12158
|
+
confidence: { type: string, nullable: true }
|
|
12159
|
+
why_we_believe_this: { type: array, items: { type: object } }
|
|
12160
|
+
corrected_by_a_human: { type: boolean }
|
|
12161
|
+
raw_observations: { type: array, items: { type: object } }
|
|
12162
|
+
note: { type: string }
|
|
12163
|
+
"403":
|
|
12164
|
+
$ref: "#/components/responses/Forbidden"
|
|
12165
|
+
"404":
|
|
12166
|
+
$ref: "#/components/responses/NotFound"
|
|
12167
|
+
|
|
12168
|
+
/v1/peers/{peer_id}/data:
|
|
12169
|
+
delete:
|
|
12170
|
+
tags: [Memory]
|
|
12171
|
+
summary: Forget this person
|
|
12172
|
+
description: |
|
|
12173
|
+
Deletes the peer, its facts and its observations. Human users only,
|
|
12174
|
+
behind strong-factor re-auth, and irreversible.
|
|
12175
|
+
|
|
12176
|
+
Returns counts of what was removed — "deleted" with no numbers is not
|
|
12177
|
+
something anyone can check. The audit entry records that a deletion
|
|
12178
|
+
happened and deliberately omits the identifier someone asked to have
|
|
12179
|
+
forgotten.
|
|
12180
|
+
operationId: deletePeerData
|
|
12181
|
+
parameters:
|
|
12182
|
+
- name: peer_id
|
|
12183
|
+
in: path
|
|
12184
|
+
required: true
|
|
12185
|
+
schema: { type: string, format: uuid }
|
|
12186
|
+
responses:
|
|
12187
|
+
"200":
|
|
12188
|
+
description: Deleted
|
|
12189
|
+
content:
|
|
12190
|
+
application/json:
|
|
12191
|
+
schema:
|
|
12192
|
+
type: object
|
|
12193
|
+
properties:
|
|
12194
|
+
deleted: { type: boolean }
|
|
12195
|
+
facts_deleted: { type: integer }
|
|
12196
|
+
observations_deleted: { type: integer }
|
|
12197
|
+
"403":
|
|
12198
|
+
$ref: "#/components/responses/Forbidden"
|
|
12199
|
+
"404":
|
|
12200
|
+
$ref: "#/components/responses/NotFound"
|
|
12201
|
+
|
|
12202
|
+
/v1/peers/{peer_id}/facts:
|
|
12203
|
+
patch:
|
|
12204
|
+
tags: [Memory]
|
|
12205
|
+
summary: Correct what the system believes
|
|
12206
|
+
description: |
|
|
12207
|
+
Human users only. A correction **pins** the fact: the background
|
|
12208
|
+
processor will not re-derive over it, because someone correcting what a
|
|
12209
|
+
system believes about them outranks the inference that got it wrong.
|
|
12210
|
+
|
|
12211
|
+
The correction is appended to the fact's provenance as a `human` entry,
|
|
12212
|
+
so the record shows both what was inferred and that a person disagreed.
|
|
12213
|
+
operationId: editPeerFact
|
|
12214
|
+
parameters:
|
|
12215
|
+
- name: peer_id
|
|
12216
|
+
in: path
|
|
12217
|
+
required: true
|
|
12218
|
+
schema: { type: string, format: uuid }
|
|
12219
|
+
requestBody:
|
|
12220
|
+
required: true
|
|
12221
|
+
content:
|
|
12222
|
+
application/json:
|
|
12223
|
+
schema:
|
|
12224
|
+
type: object
|
|
12225
|
+
required: [fact_key, fact_value]
|
|
12226
|
+
properties:
|
|
12227
|
+
fact_key: { type: string }
|
|
12228
|
+
fact_value: { type: object }
|
|
12229
|
+
responses:
|
|
12230
|
+
"200":
|
|
12231
|
+
description: Corrected
|
|
12232
|
+
content:
|
|
12233
|
+
application/json:
|
|
12234
|
+
schema:
|
|
12235
|
+
type: object
|
|
12236
|
+
properties:
|
|
12237
|
+
fact_key: { type: string }
|
|
12238
|
+
edited_by_human: { type: boolean }
|
|
12239
|
+
note: { type: string }
|
|
12240
|
+
"403":
|
|
12241
|
+
$ref: "#/components/responses/Forbidden"
|
|
12242
|
+
"404":
|
|
12243
|
+
$ref: "#/components/responses/NotFound"
|
|
12244
|
+
|
|
12245
|
+
/v1/peers/{peer_id}/context:
|
|
12246
|
+
get:
|
|
12247
|
+
tags: [Memory]
|
|
12248
|
+
summary: A context blob for prompt injection
|
|
12249
|
+
description: |
|
|
12250
|
+
What this person's history suggests, as prose an agent can put in a
|
|
12251
|
+
prompt. Best-supported facts first, so a tight budget drops the
|
|
12252
|
+
least-supported beliefs rather than an arbitrary tail — and a fact a
|
|
12253
|
+
human corrected sorts ahead of everything, because a correction someone
|
|
12254
|
+
took the trouble to make is the last thing to cut.
|
|
12255
|
+
|
|
12256
|
+
Never truncates mid-line: half a sentence about a person is worse than
|
|
12257
|
+
one fewer sentence. A peer with no facts returns an empty string rather
|
|
12258
|
+
than a header claiming to describe someone.
|
|
12259
|
+
|
|
12260
|
+
The blob ends by saying these are observations and not instructions,
|
|
12261
|
+
because an agent reading it needs to know the difference.
|
|
12262
|
+
operationId: getPeerContext
|
|
12263
|
+
parameters:
|
|
12264
|
+
- name: peer_id
|
|
12265
|
+
in: path
|
|
12266
|
+
required: true
|
|
12267
|
+
schema: { type: string, format: uuid }
|
|
12268
|
+
- name: budget
|
|
12269
|
+
in: query
|
|
12270
|
+
description: Characters. Default 2000, capped at 8000.
|
|
12271
|
+
schema: { type: integer }
|
|
12272
|
+
responses:
|
|
12273
|
+
"200":
|
|
12274
|
+
description: Context
|
|
12275
|
+
content:
|
|
12276
|
+
application/json:
|
|
12277
|
+
schema:
|
|
12278
|
+
type: object
|
|
12279
|
+
properties:
|
|
12280
|
+
context: { type: string }
|
|
12281
|
+
characters: { type: integer }
|
|
12282
|
+
budget: { type: integer }
|
|
12283
|
+
facts_available: { type: integer }
|
|
12284
|
+
"403":
|
|
12285
|
+
$ref: "#/components/responses/Forbidden"
|
|
12286
|
+
"404":
|
|
12287
|
+
$ref: "#/components/responses/NotFound"
|
|
12288
|
+
|
|
12289
|
+
/v1/agents/{agent_id}/peer-context:
|
|
12290
|
+
get:
|
|
12291
|
+
tags: [Memory]
|
|
12292
|
+
summary: An agent's own peer context
|
|
12293
|
+
description: |
|
|
12294
|
+
Resolves the peer from the agent's platform connection, so an agent does
|
|
12295
|
+
not need to know a peer id.
|
|
12296
|
+
|
|
12297
|
+
An agent may only ask for its own — otherwise this route would be a way
|
|
12298
|
+
to read a peer through an agent that observes it, from one that does not.
|
|
12299
|
+
The observer check still applies: being the agent named in the path is
|
|
12300
|
+
not the same as observing that connection's peer.
|
|
12301
|
+
operationId: getAgentPeerContext
|
|
12302
|
+
parameters:
|
|
12303
|
+
- name: agent_id
|
|
12304
|
+
in: path
|
|
12305
|
+
required: true
|
|
12306
|
+
schema: { type: string, format: uuid }
|
|
12307
|
+
- name: budget
|
|
12308
|
+
in: query
|
|
12309
|
+
schema: { type: integer }
|
|
12310
|
+
responses:
|
|
12311
|
+
"200":
|
|
12312
|
+
description: Context
|
|
12313
|
+
content:
|
|
12314
|
+
application/json:
|
|
12315
|
+
schema:
|
|
12316
|
+
type: object
|
|
12317
|
+
properties:
|
|
12318
|
+
peer_id: { type: string, format: uuid }
|
|
12319
|
+
context: { type: string }
|
|
12320
|
+
characters: { type: integer }
|
|
12321
|
+
"403":
|
|
12322
|
+
$ref: "#/components/responses/Forbidden"
|
|
12323
|
+
"404":
|
|
12324
|
+
$ref: "#/components/responses/NotFound"
|
|
12325
|
+
|
|
12326
|
+
/v1/peers/{peer_id}:
|
|
12327
|
+
get:
|
|
12328
|
+
tags: [Memory]
|
|
12329
|
+
summary: A peer's profile and derived facts
|
|
12330
|
+
description: |
|
|
12331
|
+
A peer is a shared model of one human, across the agents serving them.
|
|
12332
|
+
|
|
12333
|
+
**An agent reaches a peer only by being named in its observer list.**
|
|
12334
|
+
Being in the same organisation, the same platform connection, or holding
|
|
12335
|
+
a broad scope grants nothing. A peer with no observers is readable by no
|
|
12336
|
+
agent at all — forgetting to set observers must not expose someone's
|
|
12337
|
+
behavioural profile to every agent in the org.
|
|
12338
|
+
|
|
12339
|
+
A peer in another organisation returns 404, the same as an unknown id:
|
|
12340
|
+
whether one exists elsewhere is not something a caller should learn.
|
|
12341
|
+
|
|
12342
|
+
Each fact carries `provenance` — why it is believed. Entries for events
|
|
12343
|
+
that have since expired become tombstones keeping the shape of what was
|
|
12344
|
+
seen without the content, so a belief about a person always has a
|
|
12345
|
+
recoverable basis.
|
|
12346
|
+
operationId: getPeer
|
|
12347
|
+
parameters:
|
|
12348
|
+
- name: peer_id
|
|
12349
|
+
in: path
|
|
12350
|
+
required: true
|
|
12351
|
+
schema: { type: string, format: uuid }
|
|
12352
|
+
responses:
|
|
12353
|
+
"200":
|
|
12354
|
+
description: Peer and facts
|
|
12355
|
+
content:
|
|
12356
|
+
application/json:
|
|
12357
|
+
schema:
|
|
12358
|
+
type: object
|
|
12359
|
+
properties:
|
|
12360
|
+
peer: { $ref: "#/components/schemas/Peer" }
|
|
12361
|
+
facts:
|
|
12362
|
+
type: array
|
|
12363
|
+
items: { $ref: "#/components/schemas/PeerFact" }
|
|
12364
|
+
"403":
|
|
12365
|
+
$ref: "#/components/responses/Forbidden"
|
|
12366
|
+
"404":
|
|
12367
|
+
$ref: "#/components/responses/NotFound"
|
|
12368
|
+
|
|
12369
|
+
/v1/peers/{peer_id}/events:
|
|
12370
|
+
post:
|
|
12371
|
+
tags: [Memory]
|
|
12372
|
+
summary: Record something observed about a person
|
|
12373
|
+
operationId: recordPeerEvent
|
|
12374
|
+
parameters:
|
|
12375
|
+
- name: peer_id
|
|
12376
|
+
in: path
|
|
12377
|
+
required: true
|
|
12378
|
+
schema: { type: string, format: uuid }
|
|
12379
|
+
requestBody:
|
|
12380
|
+
required: true
|
|
12381
|
+
content:
|
|
12382
|
+
application/json:
|
|
12383
|
+
schema:
|
|
12384
|
+
type: object
|
|
12385
|
+
required: [event_type, content]
|
|
12386
|
+
properties:
|
|
12387
|
+
event_type:
|
|
12388
|
+
type: string
|
|
12389
|
+
enum: [message, approval, action, observation]
|
|
12390
|
+
content: { type: object, additionalProperties: true }
|
|
12391
|
+
responses:
|
|
12392
|
+
"201":
|
|
12393
|
+
description: Recorded
|
|
12394
|
+
content:
|
|
12395
|
+
application/json:
|
|
12396
|
+
schema:
|
|
12397
|
+
type: object
|
|
12398
|
+
properties:
|
|
12399
|
+
event_id: { type: string, format: uuid }
|
|
12400
|
+
"400":
|
|
12401
|
+
$ref: "#/components/responses/BadRequest"
|
|
12402
|
+
"403":
|
|
12403
|
+
$ref: "#/components/responses/Forbidden"
|
|
12404
|
+
"404":
|
|
12405
|
+
$ref: "#/components/responses/NotFound"
|
|
12406
|
+
|
|
12407
|
+
/v1/peers/{peer_id}/predict-approval:
|
|
12408
|
+
post:
|
|
12409
|
+
tags: [Memory]
|
|
12410
|
+
summary: How has this person decided this before?
|
|
12411
|
+
description: |
|
|
12412
|
+
Answers two different questions, and keeps them apart on purpose.
|
|
12413
|
+
|
|
12414
|
+
`likelihood` is an **observation about a person** — how they have decided
|
|
12415
|
+
comparable requests before. Comparable means the same fingerprint bucket,
|
|
12416
|
+
not the same action type: three approvals of $5 say nothing about $500.
|
|
12417
|
+
|
|
12418
|
+
`suggest_auto` is a **statement about a policy**. It is true only where a
|
|
12419
|
+
rule the operator already wrote would auto-approve this exact case. It is
|
|
12420
|
+
never derived from `likelihood`, and a confident model never becomes new
|
|
12421
|
+
authority. It is false, with `blocked_reason`, when:
|
|
12422
|
+
|
|
12423
|
+
* no rule covers the action (`no_matching_rule`);
|
|
12424
|
+
* a rule says a human decides (`rule_requires_approval`);
|
|
12425
|
+
* the amount is above the rule's own threshold (`above_configured_threshold`);
|
|
12426
|
+
* the derived risk tier is above the lowest (`risk_tier_requires_step_up`);
|
|
12427
|
+
* the action grants or destroys authority (`action_is_sensitive`).
|
|
12428
|
+
|
|
12429
|
+
The policy consulted is the calling agent's own, so a prediction cannot
|
|
12430
|
+
inherit authority from another agent that happens to observe the same
|
|
12431
|
+
person.
|
|
12432
|
+
operationId: predictApproval
|
|
12433
|
+
parameters:
|
|
12434
|
+
- name: peer_id
|
|
12435
|
+
in: path
|
|
12436
|
+
required: true
|
|
12437
|
+
schema: { type: string, format: uuid }
|
|
12438
|
+
requestBody:
|
|
12439
|
+
required: true
|
|
12440
|
+
content:
|
|
12441
|
+
application/json:
|
|
12442
|
+
schema:
|
|
12443
|
+
type: object
|
|
12444
|
+
required: [action_type, effective_risk_tier]
|
|
12445
|
+
properties:
|
|
12446
|
+
action_type: { type: string, example: refund.create }
|
|
12447
|
+
payload: { type: object, additionalProperties: true }
|
|
12448
|
+
effective_risk_tier:
|
|
12449
|
+
type: integer
|
|
12450
|
+
minimum: 1
|
|
12451
|
+
maximum: 3
|
|
12452
|
+
responses:
|
|
12453
|
+
"200":
|
|
12454
|
+
description: Prediction
|
|
12455
|
+
content:
|
|
12456
|
+
application/json:
|
|
12457
|
+
schema:
|
|
12458
|
+
type: object
|
|
12459
|
+
required: [reasoning, suggest_auto]
|
|
12460
|
+
properties:
|
|
12461
|
+
likelihood:
|
|
12462
|
+
type: number
|
|
12463
|
+
nullable: true
|
|
12464
|
+
description: Absent when there is no comparable history.
|
|
12465
|
+
reasoning: { type: string }
|
|
12466
|
+
suggest_auto:
|
|
12467
|
+
type: boolean
|
|
12468
|
+
description: Whether the operator's own policy already permits this.
|
|
12469
|
+
blocked_reason:
|
|
12470
|
+
type: string
|
|
12471
|
+
enum: [no_matching_rule, rule_requires_approval, above_configured_threshold, risk_tier_requires_step_up, action_is_sensitive]
|
|
12472
|
+
"403":
|
|
12473
|
+
$ref: "#/components/responses/Forbidden"
|
|
12474
|
+
"404":
|
|
12475
|
+
$ref: "#/components/responses/NotFound"
|
|
12476
|
+
|
|
12477
|
+
/v1/peers/by-connection/{connection_id}:
|
|
12478
|
+
get:
|
|
12479
|
+
tags: [Memory]
|
|
12480
|
+
summary: Resolve the peer for a platform connection
|
|
12481
|
+
operationId: getPeerByConnection
|
|
12482
|
+
parameters:
|
|
12483
|
+
- name: connection_id
|
|
12484
|
+
in: path
|
|
12485
|
+
required: true
|
|
12486
|
+
schema: { type: string, format: uuid }
|
|
12487
|
+
responses:
|
|
12488
|
+
"200":
|
|
12489
|
+
description: Peer
|
|
12490
|
+
content:
|
|
12491
|
+
application/json:
|
|
12492
|
+
schema:
|
|
12493
|
+
type: object
|
|
12494
|
+
properties:
|
|
12495
|
+
peer: { $ref: "#/components/schemas/Peer" }
|
|
12496
|
+
"403":
|
|
12497
|
+
$ref: "#/components/responses/Forbidden"
|
|
12498
|
+
"404":
|
|
12499
|
+
$ref: "#/components/responses/NotFound"
|
|
12500
|
+
|
|
12501
|
+
/v1/org/apply/diff:
|
|
12502
|
+
post:
|
|
12503
|
+
tags: [Organization]
|
|
12504
|
+
summary: What would this chart change?
|
|
12505
|
+
description: |
|
|
12506
|
+
Reconcile a chart against the org without changing anything. Human users
|
|
12507
|
+
only — a chart provisions agents, vaults and access policies, so an agent
|
|
12508
|
+
that could apply one could grant itself access to a vault it cannot
|
|
12509
|
+
currently read.
|
|
12510
|
+
|
|
12511
|
+
A POST rather than a GET because the chart is the request body, and a GET
|
|
12512
|
+
carrying a body is one many proxies and clients drop or mangle. Read-only
|
|
12513
|
+
either way.
|
|
12514
|
+
|
|
12515
|
+
The plan reports five outcomes per resource:
|
|
12516
|
+
|
|
12517
|
+
* `create` — not present, would be created.
|
|
12518
|
+
* `patch` — present, differs only in fields safe to change in place.
|
|
12519
|
+
* `unchanged` — present and matching.
|
|
12520
|
+
* `skipped_drifted` — **changed outside this chart**, so left alone.
|
|
12521
|
+
Someone edited it by hand for a reason; overwriting that because a file
|
|
12522
|
+
says otherwise is how a deployment tool destroys an incident fix.
|
|
12523
|
+
* `refused` — the chart asks for a change apply will not make. Guardrail
|
|
12524
|
+
fields are never patched here: editing them routes through the guardrail
|
|
12525
|
+
approval flow, and a reconciler writing them directly would be a way
|
|
12526
|
+
around it.
|
|
12527
|
+
|
|
12528
|
+
Pass `applied_state` from `.1claw/apply-state.json` so drift can be told
|
|
12529
|
+
from a first run — a pre-existing resource is not drifted, it was simply
|
|
12530
|
+
not created by this chart.
|
|
12531
|
+
operationId: diffChart
|
|
12532
|
+
requestBody:
|
|
12533
|
+
required: true
|
|
12534
|
+
content:
|
|
12535
|
+
application/json:
|
|
12536
|
+
schema:
|
|
12537
|
+
type: object
|
|
12538
|
+
required: [chart]
|
|
12539
|
+
properties:
|
|
12540
|
+
chart:
|
|
12541
|
+
type: object
|
|
12542
|
+
description: A chart document — `apiVersion`, `kind`, `metadata`, `spec`.
|
|
12543
|
+
applied_state:
|
|
12544
|
+
type: object
|
|
12545
|
+
additionalProperties: true
|
|
12546
|
+
description: What a previous apply recorded, keyed `kind/name`.
|
|
12547
|
+
responses:
|
|
12548
|
+
"200":
|
|
12549
|
+
description: The plan
|
|
12550
|
+
content:
|
|
12551
|
+
application/json:
|
|
12552
|
+
schema:
|
|
12553
|
+
type: object
|
|
12554
|
+
properties:
|
|
12555
|
+
chart_name: { type: string }
|
|
12556
|
+
actions:
|
|
12557
|
+
type: array
|
|
12558
|
+
items: { type: object }
|
|
12559
|
+
warnings:
|
|
12560
|
+
type: array
|
|
12561
|
+
items: { type: string }
|
|
12562
|
+
summary:
|
|
12563
|
+
type: object
|
|
12564
|
+
properties:
|
|
12565
|
+
create: { type: integer }
|
|
12566
|
+
patch: { type: integer }
|
|
12567
|
+
skipped_drifted: { type: integer }
|
|
12568
|
+
unchanged: { type: integer }
|
|
12569
|
+
refused: { type: integer }
|
|
12570
|
+
no_changes: { type: boolean }
|
|
12571
|
+
"400":
|
|
12572
|
+
$ref: "#/components/responses/BadRequest"
|
|
12573
|
+
"403":
|
|
12574
|
+
$ref: "#/components/responses/Forbidden"
|
|
12575
|
+
|
|
12576
|
+
/v1/notification-targets:
|
|
12577
|
+
get:
|
|
12578
|
+
tags: [Notifications]
|
|
12579
|
+
summary: List your notification targets
|
|
12580
|
+
operationId: listNotificationTargets
|
|
12581
|
+
responses:
|
|
12582
|
+
"200":
|
|
12583
|
+
description: Your targets
|
|
12584
|
+
content:
|
|
12585
|
+
application/json:
|
|
12586
|
+
schema:
|
|
12587
|
+
type: object
|
|
12588
|
+
properties:
|
|
12589
|
+
targets:
|
|
12590
|
+
type: array
|
|
12591
|
+
items:
|
|
12592
|
+
$ref: "#/components/schemas/NotificationTarget"
|
|
12593
|
+
post:
|
|
12594
|
+
tags: [Notifications]
|
|
12595
|
+
summary: Add a notification target
|
|
12596
|
+
description: |
|
|
12597
|
+
Where approvals and automation output reach a human: a phone number, an
|
|
12598
|
+
https webhook, an email address, or a push token.
|
|
12599
|
+
|
|
12600
|
+
An SMS target is created **unverified** and stays that way until someone
|
|
12601
|
+
proves they hold the number. Adding a number must not itself be an
|
|
12602
|
+
authorisation — otherwise a session borrowed for five minutes leaves
|
|
12603
|
+
behind a number that can approve things long after it is gone. An
|
|
12604
|
+
unverified target still receives notifications; it just cannot reply to
|
|
12605
|
+
decide one.
|
|
12606
|
+
operationId: createNotificationTarget
|
|
12607
|
+
requestBody:
|
|
12608
|
+
required: true
|
|
12609
|
+
content:
|
|
12610
|
+
application/json:
|
|
12611
|
+
schema:
|
|
12612
|
+
type: object
|
|
12613
|
+
required: [target_type, config]
|
|
12614
|
+
properties:
|
|
12615
|
+
target_type:
|
|
12616
|
+
type: string
|
|
12617
|
+
enum: [sms, webhook, expo, email]
|
|
12618
|
+
config:
|
|
12619
|
+
type: object
|
|
12620
|
+
description: |
|
|
12621
|
+
`{"phone_number": "+14155550123"}` for sms (E.164 only),
|
|
12622
|
+
`{"url": "https://…"}` for webhook (https only),
|
|
12623
|
+
`{"email": "…"}`, or `{"push_token": "…"}`.
|
|
12624
|
+
events:
|
|
12625
|
+
type: array
|
|
12626
|
+
items: { type: string }
|
|
12627
|
+
description: Empty means every event.
|
|
12628
|
+
agent_id:
|
|
12629
|
+
type: string
|
|
12630
|
+
format: uuid
|
|
12631
|
+
description: The agent whose SMS channel sends to this target.
|
|
12632
|
+
user_id:
|
|
12633
|
+
type: string
|
|
12634
|
+
format: uuid
|
|
12635
|
+
description: Defaults to the caller.
|
|
12636
|
+
responses:
|
|
12637
|
+
"201":
|
|
12638
|
+
description: Target created, unverified
|
|
12639
|
+
content:
|
|
12640
|
+
application/json:
|
|
12641
|
+
schema:
|
|
12642
|
+
$ref: "#/components/schemas/NotificationTarget"
|
|
12643
|
+
"400":
|
|
12644
|
+
$ref: "#/components/responses/BadRequest"
|
|
12645
|
+
"403":
|
|
12646
|
+
$ref: "#/components/responses/Forbidden"
|
|
12647
|
+
"409":
|
|
12648
|
+
$ref: "#/components/responses/Conflict"
|
|
12649
|
+
|
|
12650
|
+
/v1/notification-targets/{id}:
|
|
12651
|
+
delete:
|
|
12652
|
+
tags: [Notifications]
|
|
12653
|
+
summary: Remove a notification target
|
|
12654
|
+
operationId: deleteNotificationTarget
|
|
12655
|
+
parameters:
|
|
12656
|
+
- name: id
|
|
12657
|
+
in: path
|
|
12658
|
+
required: true
|
|
12659
|
+
schema: { type: string, format: uuid }
|
|
12660
|
+
responses:
|
|
12661
|
+
"204":
|
|
12662
|
+
description: Removed
|
|
12663
|
+
"403":
|
|
12664
|
+
$ref: "#/components/responses/Forbidden"
|
|
12665
|
+
"404":
|
|
12666
|
+
$ref: "#/components/responses/NotFound"
|
|
12667
|
+
|
|
12668
|
+
/v1/notification-targets/{id}/verify/start:
|
|
12669
|
+
post:
|
|
12670
|
+
tags: [Notifications]
|
|
12671
|
+
summary: Text a verification code to an SMS target
|
|
12672
|
+
description: |
|
|
12673
|
+
Sends a six-digit code from the same channel the target's notifications
|
|
12674
|
+
will come from — a code arriving from a different number than the one
|
|
12675
|
+
the recipient will later see is a code they are right to distrust.
|
|
12676
|
+
|
|
12677
|
+
Expires in 10 minutes. Five wrong answers void it.
|
|
12678
|
+
operationId: startNotificationTargetVerification
|
|
12679
|
+
parameters:
|
|
12680
|
+
- name: id
|
|
12681
|
+
in: path
|
|
12682
|
+
required: true
|
|
12683
|
+
schema: { type: string, format: uuid }
|
|
12684
|
+
responses:
|
|
12685
|
+
"200":
|
|
12686
|
+
description: Code sent
|
|
12687
|
+
content:
|
|
12688
|
+
application/json:
|
|
12689
|
+
schema:
|
|
12690
|
+
type: object
|
|
12691
|
+
properties:
|
|
12692
|
+
message: { type: string }
|
|
12693
|
+
expires_in_seconds: { type: integer }
|
|
12694
|
+
"400":
|
|
12695
|
+
$ref: "#/components/responses/BadRequest"
|
|
12696
|
+
"403":
|
|
12697
|
+
$ref: "#/components/responses/Forbidden"
|
|
12698
|
+
"404":
|
|
12699
|
+
$ref: "#/components/responses/NotFound"
|
|
12700
|
+
|
|
12701
|
+
/v1/notification-targets/{id}/verify:
|
|
12702
|
+
post:
|
|
12703
|
+
tags: [Notifications]
|
|
12704
|
+
summary: Submit the verification code
|
|
12705
|
+
operationId: completeNotificationTargetVerification
|
|
12706
|
+
parameters:
|
|
12707
|
+
- name: id
|
|
12708
|
+
in: path
|
|
12709
|
+
required: true
|
|
12710
|
+
schema: { type: string, format: uuid }
|
|
12711
|
+
requestBody:
|
|
12712
|
+
required: true
|
|
12713
|
+
content:
|
|
12714
|
+
application/json:
|
|
12715
|
+
schema:
|
|
12716
|
+
type: object
|
|
12717
|
+
required: [code]
|
|
12718
|
+
properties:
|
|
12719
|
+
code: { type: string, example: "042913" }
|
|
12720
|
+
responses:
|
|
12721
|
+
"200":
|
|
12722
|
+
description: Verified
|
|
12723
|
+
content:
|
|
12724
|
+
application/json:
|
|
12725
|
+
schema:
|
|
12726
|
+
type: object
|
|
12727
|
+
properties:
|
|
12728
|
+
verified: { type: boolean }
|
|
12729
|
+
"400":
|
|
12730
|
+
$ref: "#/components/responses/BadRequest"
|
|
12731
|
+
"403":
|
|
12732
|
+
$ref: "#/components/responses/Forbidden"
|
|
12733
|
+
"404":
|
|
12734
|
+
$ref: "#/components/responses/NotFound"
|
|
12735
|
+
|
|
12736
|
+
/v1/webhooks/sms/{webhook_path}:
|
|
12737
|
+
post:
|
|
12738
|
+
tags: [Channels]
|
|
12739
|
+
summary: Inbound SMS webhook (Twilio)
|
|
12740
|
+
description: |
|
|
12741
|
+
Called by Twilio when someone texts the channel's number. Public, because
|
|
12742
|
+
the provider calls it — so the `X-Twilio-Signature` header is the only
|
|
12743
|
+
thing establishing that a message is genuine, and it is verified over the
|
|
12744
|
+
exact public URL and every POST parameter.
|
|
12745
|
+
|
|
12746
|
+
A verified signature proves the message came from Twilio, **not** that it
|
|
12747
|
+
came from the right person: anyone who knows the number can text it and
|
|
12748
|
+
their message arrives correctly signed. So the sending number must also
|
|
12749
|
+
match a *verified* SMS notification target.
|
|
12750
|
+
|
|
12751
|
+
A reply may decide an approval only when its server-derived
|
|
12752
|
+
`risk_tier` is 1. Anything higher is answered with a link to confirm in
|
|
12753
|
+
the app; replying cannot decide it. When more than one approval is
|
|
12754
|
+
pending, a bare YES/NO is answered with a request for the reference code
|
|
12755
|
+
rather than applied to a guess.
|
|
12756
|
+
|
|
12757
|
+
Always answers 200 with TwiML — a non-2xx makes Twilio retry a message
|
|
12758
|
+
that was deliberately refused. The exception is a bad signature, which is
|
|
12759
|
+
403, because a persistently failing signature is a misconfiguration as
|
|
12760
|
+
often as an attack and silence would hide both.
|
|
12761
|
+
operationId: smsWebhook
|
|
12762
|
+
security: []
|
|
12763
|
+
parameters:
|
|
12764
|
+
- name: webhook_path
|
|
12765
|
+
in: path
|
|
12766
|
+
required: true
|
|
12767
|
+
schema: { type: string }
|
|
12768
|
+
- name: X-Twilio-Signature
|
|
12769
|
+
in: header
|
|
12770
|
+
required: true
|
|
12771
|
+
schema: { type: string }
|
|
12772
|
+
requestBody:
|
|
12773
|
+
required: true
|
|
12774
|
+
content:
|
|
12775
|
+
application/x-www-form-urlencoded:
|
|
12776
|
+
schema:
|
|
12777
|
+
type: object
|
|
12778
|
+
properties:
|
|
12779
|
+
From: { type: string, example: "+14155550123" }
|
|
12780
|
+
To: { type: string, example: "+14155550999" }
|
|
12781
|
+
Body: { type: string, example: "YES A1" }
|
|
12782
|
+
responses:
|
|
12783
|
+
"200":
|
|
12784
|
+
description: TwiML response; `<Response/>` when there is nothing to reply
|
|
12785
|
+
content:
|
|
12786
|
+
application/xml:
|
|
12787
|
+
schema: { type: string }
|
|
12788
|
+
"403":
|
|
12789
|
+
$ref: "#/components/responses/Forbidden"
|
|
12790
|
+
"404":
|
|
12791
|
+
$ref: "#/components/responses/NotFound"
|
|
12792
|
+
|
|
12793
|
+
/v1/webhooks/discord/{webhook_path}:
|
|
12794
|
+
post:
|
|
12795
|
+
tags: [Agent Channels]
|
|
12796
|
+
summary: Discord webhook
|
|
12797
|
+
description: Public webhook endpoint for receiving Discord bot interactions.
|
|
12798
|
+
operationId: discordWebhook
|
|
12799
|
+
security: []
|
|
12800
|
+
parameters:
|
|
12801
|
+
- name: webhook_path
|
|
12802
|
+
in: path
|
|
12803
|
+
required: true
|
|
12804
|
+
schema:
|
|
12805
|
+
type: string
|
|
12806
|
+
requestBody:
|
|
12807
|
+
required: true
|
|
12808
|
+
content:
|
|
12809
|
+
application/json:
|
|
12810
|
+
schema:
|
|
12811
|
+
type: object
|
|
12812
|
+
responses:
|
|
12813
|
+
"200":
|
|
12814
|
+
description: Webhook processed
|
|
12815
|
+
|
|
12816
|
+
# ---------------------------------------------------------------------------
|
|
12817
|
+
# OAuth Connect
|
|
12818
|
+
# ---------------------------------------------------------------------------
|
|
12819
|
+
|
|
12820
|
+
/v1/oauth/providers:
|
|
12821
|
+
get:
|
|
12822
|
+
tags: [OAuth Connect]
|
|
12823
|
+
summary: List OAuth providers
|
|
12824
|
+
description: |
|
|
12825
|
+
Returns the list of supported OAuth providers with their metadata,
|
|
12826
|
+
available scopes, and authorization URLs. No authentication required.
|
|
12827
|
+
operationId: listOAuthProviders
|
|
12828
|
+
security: []
|
|
12829
|
+
responses:
|
|
12830
|
+
"200":
|
|
12831
|
+
description: Provider list
|
|
12832
|
+
content:
|
|
12833
|
+
application/json:
|
|
12834
|
+
schema:
|
|
12835
|
+
$ref: "#/components/schemas/OAuthProviderListResponse"
|
|
12836
|
+
|
|
12837
|
+
/v1/connectors/presets:
|
|
12838
|
+
get:
|
|
12839
|
+
tags: [Connectors]
|
|
12840
|
+
summary: List connector presets
|
|
12841
|
+
description: |
|
|
12842
|
+
The catalogue of pre-built connectors — Gmail, Slack, GitHub and the rest.
|
|
12843
|
+
Each preset carries the OAuth provider and scopes to request, plus the
|
|
12844
|
+
binding config and host/path guardrails the agent will execute under.
|
|
12845
|
+
|
|
12846
|
+
No authentication required: this describes what 1Claw supports, not
|
|
12847
|
+
anything belonging to an organisation.
|
|
12848
|
+
operationId: listConnectorPresets
|
|
12849
|
+
security: []
|
|
12850
|
+
responses:
|
|
12851
|
+
"200":
|
|
12852
|
+
description: Preset catalogue
|
|
12853
|
+
content:
|
|
12854
|
+
application/json:
|
|
12855
|
+
schema:
|
|
12856
|
+
type: object
|
|
12857
|
+
properties:
|
|
12858
|
+
presets:
|
|
12859
|
+
type: array
|
|
12860
|
+
items:
|
|
12861
|
+
$ref: "#/components/schemas/ConnectorPreset"
|
|
12862
|
+
|
|
12863
|
+
/v1/agents/{agent_id}/connectors:
|
|
12864
|
+
get:
|
|
12865
|
+
tags: [Connectors]
|
|
12866
|
+
summary: List installed connectors
|
|
12867
|
+
description: |
|
|
12868
|
+
Connectors installed on this agent, and whether each one has actually
|
|
12869
|
+
been connected — an install creates the binding, but the binding is not
|
|
12870
|
+
usable until the OAuth round trip completes.
|
|
12871
|
+
operationId: listInstalledConnectors
|
|
12872
|
+
parameters:
|
|
12873
|
+
- name: agent_id
|
|
12874
|
+
in: path
|
|
12875
|
+
required: true
|
|
12876
|
+
schema: { type: string, format: uuid }
|
|
12877
|
+
responses:
|
|
12878
|
+
"200":
|
|
12879
|
+
description: Installed connectors
|
|
12880
|
+
content:
|
|
12881
|
+
application/json:
|
|
12882
|
+
schema:
|
|
12883
|
+
type: object
|
|
12884
|
+
properties:
|
|
12885
|
+
connectors:
|
|
12886
|
+
type: array
|
|
12887
|
+
items:
|
|
12888
|
+
$ref: "#/components/schemas/InstalledConnector"
|
|
12889
|
+
"403":
|
|
12890
|
+
$ref: "#/components/responses/Forbidden"
|
|
12891
|
+
"404":
|
|
12892
|
+
$ref: "#/components/responses/NotFound"
|
|
12893
|
+
|
|
12894
|
+
/v1/agents/{agent_id}/connectors/{slug}/install:
|
|
12895
|
+
post:
|
|
12896
|
+
tags: [Connectors]
|
|
12897
|
+
summary: Install a connector
|
|
12898
|
+
description: |
|
|
12899
|
+
Creates a binding from the preset — base URL, allowed hosts, allowed
|
|
12900
|
+
paths — and starts the OAuth flow for it. Send the user to the returned
|
|
12901
|
+
`authorization_url` to finish; until they do, the binding exists but
|
|
12902
|
+
holds no credential.
|
|
12903
|
+
|
|
12904
|
+
Human users only. Installing gives an agent reach into a third-party
|
|
12905
|
+
account, and the flow it starts is a person's browser.
|
|
12906
|
+
|
|
12907
|
+
Idempotent by binding name: re-installing re-runs the OAuth flow against
|
|
12908
|
+
the existing binding rather than creating a second one holding a second
|
|
12909
|
+
token for the same account. A name already taken by a binding that is
|
|
12910
|
+
not this connector returns 409.
|
|
12911
|
+
operationId: installConnector
|
|
12912
|
+
parameters:
|
|
12913
|
+
- name: agent_id
|
|
12914
|
+
in: path
|
|
12915
|
+
required: true
|
|
12916
|
+
schema: { type: string, format: uuid }
|
|
12917
|
+
- name: slug
|
|
12918
|
+
in: path
|
|
12919
|
+
required: true
|
|
12920
|
+
description: Connector preset slug, e.g. `gmail`.
|
|
12921
|
+
schema: { type: string }
|
|
12922
|
+
requestBody:
|
|
12923
|
+
required: true
|
|
12924
|
+
content:
|
|
12925
|
+
application/json:
|
|
12926
|
+
schema:
|
|
12927
|
+
type: object
|
|
12928
|
+
properties:
|
|
12929
|
+
binding_name:
|
|
12930
|
+
type: string
|
|
12931
|
+
description: Defaults to the preset slug.
|
|
12932
|
+
scopes:
|
|
12933
|
+
type: array
|
|
12934
|
+
items: { type: string }
|
|
12935
|
+
description: |
|
|
12936
|
+
Narrow the preset's scopes. Widening is refused — the
|
|
12937
|
+
preset's scope list is the reviewed part of a one-click
|
|
12938
|
+
install. Must still include the preset's required scopes.
|
|
12939
|
+
redirect_after:
|
|
12940
|
+
type: string
|
|
12941
|
+
description: Where to send the user after the OAuth round trip.
|
|
12942
|
+
responses:
|
|
12943
|
+
"201":
|
|
12944
|
+
description: Connector installed; OAuth may still be pending
|
|
12945
|
+
content:
|
|
12946
|
+
application/json:
|
|
12947
|
+
schema:
|
|
12948
|
+
type: object
|
|
12949
|
+
required: [binding_id, binding_name, preset_slug, next_step]
|
|
12950
|
+
properties:
|
|
12951
|
+
binding_id: { type: string, format: uuid }
|
|
12952
|
+
binding_name: { type: string }
|
|
12953
|
+
preset_slug: { type: string }
|
|
12954
|
+
authorization_url:
|
|
12955
|
+
type: string
|
|
12956
|
+
nullable: true
|
|
12957
|
+
description: Absent for connectors that use a pasted API key rather than OAuth.
|
|
12958
|
+
next_step:
|
|
12959
|
+
type: string
|
|
12960
|
+
description: What the user still has to do, in words.
|
|
12961
|
+
"400":
|
|
12962
|
+
$ref: "#/components/responses/BadRequest"
|
|
12963
|
+
"403":
|
|
12964
|
+
$ref: "#/components/responses/Forbidden"
|
|
12965
|
+
"404":
|
|
12966
|
+
$ref: "#/components/responses/NotFound"
|
|
12967
|
+
"409":
|
|
12968
|
+
$ref: "#/components/responses/Conflict"
|
|
12969
|
+
|
|
12970
|
+
/v1/agents/{agent_id}/oauth/connect:
|
|
12971
|
+
post:
|
|
12972
|
+
tags: [OAuth Connect]
|
|
12973
|
+
summary: Initiate OAuth connection
|
|
12974
|
+
description: |
|
|
12975
|
+
Start an OAuth authorization flow for the specified agent and provider.
|
|
12976
|
+
Returns the authorization URL to redirect the user to. Human-only.
|
|
12977
|
+
operationId: connectOAuth
|
|
12978
|
+
parameters:
|
|
12979
|
+
- $ref: "#/components/parameters/AgentId"
|
|
12980
|
+
requestBody:
|
|
12981
|
+
required: true
|
|
12982
|
+
content:
|
|
12983
|
+
application/json:
|
|
12984
|
+
schema:
|
|
12985
|
+
$ref: "#/components/schemas/ConnectOAuthRequest"
|
|
12986
|
+
responses:
|
|
12987
|
+
"200":
|
|
12988
|
+
description: Authorization URL generated
|
|
12989
|
+
content:
|
|
12990
|
+
application/json:
|
|
12991
|
+
schema:
|
|
12992
|
+
$ref: "#/components/schemas/ConnectOAuthResponse"
|
|
12993
|
+
"400":
|
|
12994
|
+
$ref: "#/components/responses/BadRequest"
|
|
12995
|
+
"403":
|
|
12996
|
+
$ref: "#/components/responses/Forbidden"
|
|
12997
|
+
"404":
|
|
12998
|
+
$ref: "#/components/responses/NotFound"
|
|
12999
|
+
|
|
13000
|
+
/v1/agents/{agent_id}/oauth/connections:
|
|
13001
|
+
get:
|
|
13002
|
+
tags: [OAuth Connect]
|
|
13003
|
+
summary: List OAuth connections
|
|
13004
|
+
description: List all active OAuth connections for the specified agent.
|
|
11427
13005
|
operationId: listOAuthConnections
|
|
11428
13006
|
parameters:
|
|
11429
13007
|
- $ref: "#/components/parameters/AgentId"
|
|
@@ -16041,6 +17619,22 @@ components:
|
|
|
16041
17619
|
additionalProperties: true
|
|
16042
17620
|
nullable: true
|
|
16043
17621
|
description: Graduated transaction approval policy (HITL thresholds). Separate from hard guardrails.
|
|
17622
|
+
action_approval_policy:
|
|
17623
|
+
type: object
|
|
17624
|
+
additionalProperties: true
|
|
17625
|
+
nullable: true
|
|
17626
|
+
description: |
|
|
17627
|
+
Which business actions this agent must ask a human about, and above what
|
|
17628
|
+
amount. `{}` means no per-action rules.
|
|
17629
|
+
|
|
17630
|
+
Shape: `{ "default_mode": "deny|approve|allow", "rules": [ { "action_type":
|
|
17631
|
+
"refund.create", "mode": "approve", "require_for_amount_above_usd": "50",
|
|
17632
|
+
"summary_template": "Refund {{amount_usd}} to {{customer_email}}" } ] }`.
|
|
17633
|
+
|
|
17634
|
+
A rule can only raise the bar. Editing this is classified as a guardrail
|
|
17635
|
+
widening, so it routes through the same approval flow as loosening a
|
|
17636
|
+
transaction limit. Malformed rules are rejected on write rather than
|
|
17637
|
+
ignored at request time.
|
|
16044
17638
|
typed_data_policy:
|
|
16045
17639
|
type: string
|
|
16046
17640
|
enum: [deny, approve]
|
|
@@ -16223,6 +17817,22 @@ components:
|
|
|
16223
17817
|
additionalProperties: true
|
|
16224
17818
|
nullable: true
|
|
16225
17819
|
description: Graduated transaction approval policy (HITL thresholds).
|
|
17820
|
+
action_approval_policy:
|
|
17821
|
+
type: object
|
|
17822
|
+
additionalProperties: true
|
|
17823
|
+
nullable: true
|
|
17824
|
+
description: |
|
|
17825
|
+
Which business actions this agent must ask a human about, and above what
|
|
17826
|
+
amount. `{}` means no per-action rules.
|
|
17827
|
+
|
|
17828
|
+
Shape: `{ "default_mode": "deny|approve|allow", "rules": [ { "action_type":
|
|
17829
|
+
"refund.create", "mode": "approve", "require_for_amount_above_usd": "50",
|
|
17830
|
+
"summary_template": "Refund {{amount_usd}} to {{customer_email}}" } ] }`.
|
|
17831
|
+
|
|
17832
|
+
A rule can only raise the bar. Editing this is classified as a guardrail
|
|
17833
|
+
widening, so it routes through the same approval flow as loosening a
|
|
17834
|
+
transaction limit. Malformed rules are rejected on write rather than
|
|
17835
|
+
ignored at request time.
|
|
16226
17836
|
typed_data_policy:
|
|
16227
17837
|
type: string
|
|
16228
17838
|
enum: [deny, approve]
|
|
@@ -16494,6 +18104,22 @@ components:
|
|
|
16494
18104
|
additionalProperties: true
|
|
16495
18105
|
nullable: true
|
|
16496
18106
|
description: Graduated transaction approval policy (HITL thresholds).
|
|
18107
|
+
action_approval_policy:
|
|
18108
|
+
type: object
|
|
18109
|
+
additionalProperties: true
|
|
18110
|
+
nullable: true
|
|
18111
|
+
description: |
|
|
18112
|
+
Which business actions this agent must ask a human about, and above what
|
|
18113
|
+
amount. `{}` means no per-action rules.
|
|
18114
|
+
|
|
18115
|
+
Shape: `{ "default_mode": "deny|approve|allow", "rules": [ { "action_type":
|
|
18116
|
+
"refund.create", "mode": "approve", "require_for_amount_above_usd": "50",
|
|
18117
|
+
"summary_template": "Refund {{amount_usd}} to {{customer_email}}" } ] }`.
|
|
18118
|
+
|
|
18119
|
+
A rule can only raise the bar. Editing this is classified as a guardrail
|
|
18120
|
+
widening, so it routes through the same approval flow as loosening a
|
|
18121
|
+
transaction limit. Malformed rules are rejected on write rather than
|
|
18122
|
+
ignored at request time.
|
|
16497
18123
|
typed_data_policy:
|
|
16498
18124
|
type: string
|
|
16499
18125
|
enum: [deny, approve]
|
|
@@ -19969,6 +21595,140 @@ components:
|
|
|
19969
21595
|
type: string
|
|
19970
21596
|
format: date-time
|
|
19971
21597
|
|
|
21598
|
+
FleetSummaryResponse:
|
|
21599
|
+
type: object
|
|
21600
|
+
properties:
|
|
21601
|
+
template_id:
|
|
21602
|
+
type: string
|
|
21603
|
+
format: uuid
|
|
21604
|
+
template_name:
|
|
21605
|
+
type: string
|
|
21606
|
+
current_version:
|
|
21607
|
+
type: integer
|
|
21608
|
+
spec_hash:
|
|
21609
|
+
type: [string, "null"]
|
|
21610
|
+
description: >
|
|
21611
|
+
SHA-256 of the template spec. Lets a caller tell a version bump that
|
|
21612
|
+
changed nothing from one that did. Null on templates written before
|
|
21613
|
+
migration 245.
|
|
21614
|
+
total_agents:
|
|
21615
|
+
type: integer
|
|
21616
|
+
format: int64
|
|
21617
|
+
version_skew:
|
|
21618
|
+
type: array
|
|
21619
|
+
description: How the cohort splits across the versions it was provisioned from.
|
|
21620
|
+
items:
|
|
21621
|
+
type: object
|
|
21622
|
+
properties:
|
|
21623
|
+
template_version:
|
|
21624
|
+
type: [integer, "null"]
|
|
21625
|
+
agents:
|
|
21626
|
+
type: integer
|
|
21627
|
+
format: int64
|
|
21628
|
+
agents_on_current_version:
|
|
21629
|
+
type: integer
|
|
21630
|
+
format: int64
|
|
21631
|
+
agents_behind:
|
|
21632
|
+
type: integer
|
|
21633
|
+
format: int64
|
|
21634
|
+
drifted_agents:
|
|
21635
|
+
type: integer
|
|
21636
|
+
format: int64
|
|
21637
|
+
description: Agents a previous rollout declined to touch.
|
|
21638
|
+
bulk_patchable_fields:
|
|
21639
|
+
type: array
|
|
21640
|
+
description: >
|
|
21641
|
+
The fields bulk-patch and rollout will carry. Read this rather than
|
|
21642
|
+
hard-coding the list; it is deliberately narrower than a single-agent
|
|
21643
|
+
PATCH and may narrow further.
|
|
21644
|
+
items:
|
|
21645
|
+
type: string
|
|
21646
|
+
|
|
21647
|
+
ListFleetAgentsResponse:
|
|
21648
|
+
type: object
|
|
21649
|
+
properties:
|
|
21650
|
+
agents:
|
|
21651
|
+
type: array
|
|
21652
|
+
items:
|
|
21653
|
+
$ref: "#/components/schemas/FleetAgent"
|
|
21654
|
+
limit:
|
|
21655
|
+
type: integer
|
|
21656
|
+
offset:
|
|
21657
|
+
type: integer
|
|
21658
|
+
current_version:
|
|
21659
|
+
type: integer
|
|
21660
|
+
|
|
21661
|
+
FleetAgent:
|
|
21662
|
+
type: object
|
|
21663
|
+
properties:
|
|
21664
|
+
agent_id:
|
|
21665
|
+
type: string
|
|
21666
|
+
format: uuid
|
|
21667
|
+
name:
|
|
21668
|
+
type: string
|
|
21669
|
+
org_id:
|
|
21670
|
+
type: string
|
|
21671
|
+
format: uuid
|
|
21672
|
+
platform_connection_id:
|
|
21673
|
+
type: [string, "null"]
|
|
21674
|
+
format: uuid
|
|
21675
|
+
provisioned_from_version:
|
|
21676
|
+
type: [integer, "null"]
|
|
21677
|
+
last_fleet_sync_at:
|
|
21678
|
+
type: [string, "null"]
|
|
21679
|
+
format: date-time
|
|
21680
|
+
drift_fields:
|
|
21681
|
+
type: array
|
|
21682
|
+
description: >
|
|
21683
|
+
Fields a rollout skipped because they were changed outside fleet
|
|
21684
|
+
control. The standing answer to "why is this agent behind?".
|
|
21685
|
+
items:
|
|
21686
|
+
type: string
|
|
21687
|
+
is_active:
|
|
21688
|
+
type: boolean
|
|
21689
|
+
is_current:
|
|
21690
|
+
type: boolean
|
|
21691
|
+
|
|
21692
|
+
FleetRolloutResponse:
|
|
21693
|
+
type: object
|
|
21694
|
+
properties:
|
|
21695
|
+
job_id:
|
|
21696
|
+
type: [string, "null"]
|
|
21697
|
+
format: uuid
|
|
21698
|
+
description: Null for a dry run, which claims no job.
|
|
21699
|
+
to_version:
|
|
21700
|
+
type: integer
|
|
21701
|
+
dry_run:
|
|
21702
|
+
type: boolean
|
|
21703
|
+
forced:
|
|
21704
|
+
type: boolean
|
|
21705
|
+
total_agents:
|
|
21706
|
+
type: integer
|
|
21707
|
+
format: int64
|
|
21708
|
+
synced:
|
|
21709
|
+
type: integer
|
|
21710
|
+
already_current:
|
|
21711
|
+
type: integer
|
|
21712
|
+
skipped_drifted:
|
|
21713
|
+
type: integer
|
|
21714
|
+
outcomes:
|
|
21715
|
+
type: array
|
|
21716
|
+
items:
|
|
21717
|
+
type: object
|
|
21718
|
+
properties:
|
|
21719
|
+
outcome:
|
|
21720
|
+
type: string
|
|
21721
|
+
enum: [already_current, synced, skipped_drifted]
|
|
21722
|
+
agent_id:
|
|
21723
|
+
type: string
|
|
21724
|
+
format: uuid
|
|
21725
|
+
fields:
|
|
21726
|
+
type: array
|
|
21727
|
+
items: { type: string }
|
|
21728
|
+
drift_fields:
|
|
21729
|
+
type: array
|
|
21730
|
+
items: { type: string }
|
|
21731
|
+
|
|
19972
21732
|
UpsertPlatformUserRequest:
|
|
19973
21733
|
type: object
|
|
19974
21734
|
properties:
|
|
@@ -20531,6 +22291,170 @@ components:
|
|
|
20531
22291
|
type: string
|
|
20532
22292
|
description: Optional human-readable reason for the decision
|
|
20533
22293
|
|
|
22294
|
+
UsageCounts:
|
|
22295
|
+
type: object
|
|
22296
|
+
required: [api_requests, signatures, execution_intents, execution_intents_tee, inference_usd, credits_debited_cents]
|
|
22297
|
+
properties:
|
|
22298
|
+
api_requests: { type: integer, format: int64 }
|
|
22299
|
+
signatures: { type: integer, format: int64 }
|
|
22300
|
+
execution_intents: { type: integer, format: int64 }
|
|
22301
|
+
execution_intents_tee: { type: integer, format: int64 }
|
|
22302
|
+
inference_usd:
|
|
22303
|
+
type: string
|
|
22304
|
+
description: A decimal string. Money is not a float; zero is "0".
|
|
22305
|
+
example: "3.42"
|
|
22306
|
+
credits_debited_cents: { type: integer, format: int64 }
|
|
22307
|
+
|
|
22308
|
+
AppUsageReport:
|
|
22309
|
+
type: object
|
|
22310
|
+
required: [app_id, period_start, period_end, connections, unattributed, totals, has_ambiguous_usage]
|
|
22311
|
+
properties:
|
|
22312
|
+
app_id: { type: string, format: uuid }
|
|
22313
|
+
period_start: { type: string, format: date-time }
|
|
22314
|
+
period_end:
|
|
22315
|
+
type: string
|
|
22316
|
+
format: date-time
|
|
22317
|
+
description: Exclusive. The period is half-open, so an event at midnight belongs to one month, not two.
|
|
22318
|
+
connections:
|
|
22319
|
+
type: array
|
|
22320
|
+
items:
|
|
22321
|
+
type: object
|
|
22322
|
+
required: [connection_id, usage]
|
|
22323
|
+
properties:
|
|
22324
|
+
connection_id: { type: string, format: uuid }
|
|
22325
|
+
usage: { $ref: "#/components/schemas/UsageCounts" }
|
|
22326
|
+
unattributed:
|
|
22327
|
+
type: object
|
|
22328
|
+
description: Usage that could not be charged to a connection.
|
|
22329
|
+
properties:
|
|
22330
|
+
ambiguous:
|
|
22331
|
+
allOf:
|
|
22332
|
+
- $ref: "#/components/schemas/UsageCounts"
|
|
22333
|
+
description: The agent belongs to several connections and none was named. This belongs to someone.
|
|
22334
|
+
none:
|
|
22335
|
+
allOf:
|
|
22336
|
+
- $ref: "#/components/schemas/UsageCounts"
|
|
22337
|
+
description: No platform linkage. Normal for most traffic.
|
|
22338
|
+
totals:
|
|
22339
|
+
allOf:
|
|
22340
|
+
- $ref: "#/components/schemas/UsageCounts"
|
|
22341
|
+
description: Connections plus both unattributed buckets. Derived, not queried.
|
|
22342
|
+
has_ambiguous_usage:
|
|
22343
|
+
type: boolean
|
|
22344
|
+
description: Some usage this period belongs to an end-user who cannot be identified.
|
|
22345
|
+
|
|
22346
|
+
Peer:
|
|
22347
|
+
type: object
|
|
22348
|
+
required: [id, peer_type, peer_ref, profile, status, observer_count, created_at]
|
|
22349
|
+
properties:
|
|
22350
|
+
id: { type: string, format: uuid }
|
|
22351
|
+
peer_type: { type: string, enum: [user, platform_connection, external] }
|
|
22352
|
+
peer_ref: { type: string }
|
|
22353
|
+
display_name: { type: string, nullable: true }
|
|
22354
|
+
profile: { type: object, additionalProperties: true }
|
|
22355
|
+
status:
|
|
22356
|
+
type: string
|
|
22357
|
+
enum: [active, archived]
|
|
22358
|
+
description: |
|
|
22359
|
+
Archived when a connection is disconnected. Agents lose observation;
|
|
22360
|
+
the person keeps export and delete.
|
|
22361
|
+
observer_count:
|
|
22362
|
+
type: integer
|
|
22363
|
+
description: How many agents observe this peer. The list itself is not returned here.
|
|
22364
|
+
created_at: { type: string, format: date-time }
|
|
22365
|
+
|
|
22366
|
+
PeerFact:
|
|
22367
|
+
type: object
|
|
22368
|
+
required: [fact_key, fact_value, provenance, edited_by_human, updated_at]
|
|
22369
|
+
properties:
|
|
22370
|
+
fact_key: { type: string, example: "approval_tendency:refund.create|0-10|known|a@b.co" }
|
|
22371
|
+
fact_value: { type: object, additionalProperties: true }
|
|
22372
|
+
confidence:
|
|
22373
|
+
type: string
|
|
22374
|
+
nullable: true
|
|
22375
|
+
description: 0..1, capped below certainty — no history makes the next decision certain.
|
|
22376
|
+
provenance:
|
|
22377
|
+
type: array
|
|
22378
|
+
items: { type: object }
|
|
22379
|
+
description: |
|
|
22380
|
+
Why this is believed. Entries are `event`, `tombstone` (the event has
|
|
22381
|
+
expired; kind and decision are kept, content is not) or `human`.
|
|
22382
|
+
edited_by_human:
|
|
22383
|
+
type: boolean
|
|
22384
|
+
description: A person corrected this. The processor will not overwrite it.
|
|
22385
|
+
updated_at: { type: string, format: date-time }
|
|
22386
|
+
|
|
22387
|
+
NotificationTarget:
|
|
22388
|
+
type: object
|
|
22389
|
+
required: [id, target_type, config, events, is_active, verified, created_at]
|
|
22390
|
+
properties:
|
|
22391
|
+
id: { type: string, format: uuid }
|
|
22392
|
+
target_type:
|
|
22393
|
+
type: string
|
|
22394
|
+
enum: [sms, webhook, expo, email]
|
|
22395
|
+
user_id: { type: string, format: uuid, nullable: true }
|
|
22396
|
+
agent_id: { type: string, format: uuid, nullable: true }
|
|
22397
|
+
config: { type: object, additionalProperties: true }
|
|
22398
|
+
events:
|
|
22399
|
+
type: array
|
|
22400
|
+
items: { type: string }
|
|
22401
|
+
is_active: { type: boolean }
|
|
22402
|
+
verified:
|
|
22403
|
+
type: boolean
|
|
22404
|
+
description: |
|
|
22405
|
+
An unverified SMS target receives notifications but cannot decide
|
|
22406
|
+
an approval by reply.
|
|
22407
|
+
created_at: { type: string, format: date-time }
|
|
22408
|
+
|
|
22409
|
+
ConnectorPreset:
|
|
22410
|
+
type: object
|
|
22411
|
+
required: [slug, display_name, description, category, binding_type, base_url, requires_oauth]
|
|
22412
|
+
properties:
|
|
22413
|
+
slug: { type: string, example: gmail }
|
|
22414
|
+
display_name: { type: string, example: Gmail }
|
|
22415
|
+
description: { type: string }
|
|
22416
|
+
category: { type: string, example: communication }
|
|
22417
|
+
provider_slug:
|
|
22418
|
+
type: string
|
|
22419
|
+
nullable: true
|
|
22420
|
+
description: "`oauth_providers.slug`, or null when the connector uses a pasted API key."
|
|
22421
|
+
oauth_scopes:
|
|
22422
|
+
type: array
|
|
22423
|
+
items: { type: string }
|
|
22424
|
+
required_scopes:
|
|
22425
|
+
type: array
|
|
22426
|
+
items: { type: string }
|
|
22427
|
+
description: Scopes without which the connector cannot do anything.
|
|
22428
|
+
binding_type: { type: string, example: http }
|
|
22429
|
+
base_url: { type: string, format: uri }
|
|
22430
|
+
allowed_hosts:
|
|
22431
|
+
type: array
|
|
22432
|
+
items: { type: string }
|
|
22433
|
+
description: Hosts the installed binding may reach. Always includes the base URL's host.
|
|
22434
|
+
documentation_url: { type: string, format: uri }
|
|
22435
|
+
tier_required: { type: string, example: free }
|
|
22436
|
+
requires_oauth: { type: boolean }
|
|
22437
|
+
|
|
22438
|
+
InstalledConnector:
|
|
22439
|
+
type: object
|
|
22440
|
+
required: [binding_id, binding_name, preset_slug, is_active, connected, needs_reauth, created_at]
|
|
22441
|
+
properties:
|
|
22442
|
+
binding_id: { type: string, format: uuid }
|
|
22443
|
+
binding_name: { type: string }
|
|
22444
|
+
preset_slug: { type: string }
|
|
22445
|
+
display_name:
|
|
22446
|
+
type: string
|
|
22447
|
+
nullable: true
|
|
22448
|
+
description: Null if the preset has since been retired from the catalogue.
|
|
22449
|
+
is_active: { type: boolean }
|
|
22450
|
+
connected:
|
|
22451
|
+
type: boolean
|
|
22452
|
+
description: The OAuth round trip completed and a token is stored.
|
|
22453
|
+
needs_reauth:
|
|
22454
|
+
type: boolean
|
|
22455
|
+
description: The stored token was rejected; the user must reconnect.
|
|
22456
|
+
created_at: { type: string, format: date-time }
|
|
22457
|
+
|
|
20534
22458
|
ApprovalResponse:
|
|
20535
22459
|
type: object
|
|
20536
22460
|
required: [id, org_id, user_id, action, target_type, target_id, risk_tier, status, summary, created_at]
|
|
@@ -20558,6 +22482,23 @@ components:
|
|
|
20558
22482
|
type: integer
|
|
20559
22483
|
minimum: 1
|
|
20560
22484
|
maximum: 3
|
|
22485
|
+
description: "The tier actually enforced. Authoritative."
|
|
22486
|
+
declared_risk_tier:
|
|
22487
|
+
type: integer
|
|
22488
|
+
minimum: 1
|
|
22489
|
+
maximum: 3
|
|
22490
|
+
nullable: true
|
|
22491
|
+
description: "What the caller asked for, when it asked for anything."
|
|
22492
|
+
declared_below_floor:
|
|
22493
|
+
type: boolean
|
|
22494
|
+
description: "The caller asked for a lower tier than policy required."
|
|
22495
|
+
human_summary:
|
|
22496
|
+
type: string
|
|
22497
|
+
nullable: true
|
|
22498
|
+
description: "Plain-language line sent to SMS, push and email."
|
|
22499
|
+
payload:
|
|
22500
|
+
type: object
|
|
22501
|
+
description: "What the action will do, as submitted."
|
|
20561
22502
|
status:
|
|
20562
22503
|
type: string
|
|
20563
22504
|
enum: [pending, approved, rejected, expired]
|
|
@@ -20912,7 +22853,7 @@ components:
|
|
|
20912
22853
|
|
|
20913
22854
|
ConnectionUsageResponse:
|
|
20914
22855
|
type: object
|
|
20915
|
-
required: [connection_id, period, inference_spent_usd]
|
|
22856
|
+
required: [connection_id, period, inference_spent_usd, usage, period_start, period_end]
|
|
20916
22857
|
properties:
|
|
20917
22858
|
connection_id:
|
|
20918
22859
|
type: string
|
|
@@ -20922,6 +22863,23 @@ components:
|
|
|
20922
22863
|
description: UTC month (YYYY-MM)
|
|
20923
22864
|
inference_spent_usd:
|
|
20924
22865
|
type: string
|
|
22866
|
+
description: |
|
|
22867
|
+
Kept for compatibility — this field predates the breakdown below and
|
|
22868
|
+
existing integrations read it. Same number as `usage.inference_usd`.
|
|
22869
|
+
usage:
|
|
22870
|
+
allOf:
|
|
22871
|
+
- $ref: "#/components/schemas/UsageCounts"
|
|
22872
|
+
description: |
|
|
22873
|
+
Everything billable for this connection in the period. Derived from the
|
|
22874
|
+
same grouped query as the app report, so a connection can never report a
|
|
22875
|
+
number the app report disagrees with.
|
|
22876
|
+
period_start:
|
|
22877
|
+
type: string
|
|
22878
|
+
format: date-time
|
|
22879
|
+
period_end:
|
|
22880
|
+
type: string
|
|
22881
|
+
format: date-time
|
|
22882
|
+
description: Exclusive. The period is half-open.
|
|
20925
22883
|
|
|
20926
22884
|
EntitlementsListResponse:
|
|
20927
22885
|
type: object
|