openapi: 3.2.0 info: title: 'Decision Anchor: The External Anchoring Layer for AI Agents…' description: Decision Anchor is the External Anchoring Layer for AI agents, providing Content-blind Accountability for agent decisions, delegations, and disputes. version: 1.3.42 contact: name: Decision Anchor email: contact@decision-anchor.com servers: - url: https://api.decision-anchor.com description: Production tags: - name: DD description: 'Decision Declaration: external decision record with accountability scope' paths: /v1/dd/create: post: tags: - DD summary: Create DD security: - AgentToken: [] requestBody: required: true content: application/json: schema: type: object required: - request_id - dd - ee properties: request_id: type: string format: uuid description: Client-generated idempotency key. MUST be a fresh UUID for every call. Reusing one of your own values returns your earlier result instead of creating a new record; the key is scoped to your agent_id, so a value another agent used never returns their record. Generate with crypto.randomUUID() or an equivalent. dd: $ref: '#/components/schemas/DDInput' ee: $ref: '#/components/schemas/EEInput' continuity: type: object description: Lineage link. Only parent_dd_id is read; other keys are ignored. The parent DD must belong to the same agent. properties: parent_dd_id: type: string format: uuid premium_payment_source: type: string enum: - external - earned content_inclusion_flag: type: integer enum: - 0 - 1 default: 0 description: Content Inclusion branch. Top-level field (not inside dd). 1 requires template. template: $ref: '#/components/schemas/TemplateInput' example: request_id: 00000000-0000-4000-8000-000000000000 dd: dd_unit_type: single dd_declaration_mode: self_declared decision_type: internal_service decision_action_type: execute origin_context_type: internal selection_state: SELECTED ee: ee_retention_period: short ee_integrity_verification_level: basic ee_disclosure_format_policy: internal ee_responsibility_scope: minimal responses: '402': $ref: '#/components/responses/PaymentRequired' '400': description: Request validation failed. Codes include MISSING_FIELD, INVALID_ENUM, UNKNOWN_FIELD, INVALID_EE_PRESET, EE_PRESET_DISABLED, and DECLARATION_MODE_NOT_ALLOWED (dd.dd_declaration_mode was a valid enum value but not self_declared; this route accepts self-declared decisions only). content: application/json: schema: $ref: '#/components/schemas/Error' '201': description: DD created. When the record is charged to external payment, confirm within 30 minutes of creation. After that the payment reservation is released and the record can no longer be confirmed. Trial-covered records carry no reservation and have no such window; confirm them whenever the action has been executed. content: application/json: schema: type: object properties: dd_id: type: string format: uuid ee_id: type: string format: uuid dac_amount: type: number pricing_version: type: string cost_breakdown: $ref: '#/components/schemas/CostBreakdown' payment_deadline: type: string format: date-time status: type: string enum: - trial_paid - pending_payment description: 'trial_paid: base fee covered by trial, so do NOT send USDC. pending_payment: external x402 payment expected.' payment: type: object description: Present ONLY for status='pending_payment' (external). OMITTED for trial_paid (nothing to pay; trial does not cross USDC). Contains the x402 payment address/amount, approx KRW (live estimate at current rate, not a settled claim), and expires_at (30-min window). trial_payment: type: object description: 'Present when the base fee was paid from trial balance: {payment_source:''trial'', trial_remaining, trial_expires_at}. Overrides any impression from ''payment'' that USDC is owed.' description: 'Response shape differs by how the base fee was covered. status=''trial_paid'': base fee was deducted from the trial balance, so NO USDC transfer is required, the ''payment'' object is OMITTED (nothing to pay), and ''trial_payment'' states the deduction. status=''pending_payment'' (external): ''payment'' carries the x402 address/amount; pay via x402 and call POST /v1/dd/confirm with dd_id (transaction_id not required).' examples: trial_paid: summary: 'Trial covered the base fee: no USDC transfer needed (payment object omitted)' value: dd_id: 00000000-0000-0000-0000-000000000001 ee_id: 00000000-0000-0000-0000-000000000002 dac_amount: 10 status: trial_paid trial_payment: payment_source: trial trial_remaining: 490 external_pending: summary: 'External: pay via x402, then POST /v1/dd/confirm {dd_id}' value: dd_id: 00000000-0000-0000-0000-000000000001 ee_id: 00000000-0000-0000-0000-000000000002 dac_amount: 10 status: pending_payment payment: payment_address: 0x... amount_usdc: 0.01 expires_at: '2026-01-01T00:30:00Z' description: 'Declare a decision and fix its accountability boundary. You say when: before an irreversible action, or after a decision you have already made. Implements Content-blind Accountability via DD (Decision Declaration): records when, at what resolution, and with what scope of accountability, but never the content of the decision itself. The accountability boundary is fixed externally so internal logs cannot retroactively rewrite it. This route accepts self-declared decisions only: dd.dd_declaration_mode must be "self_declared", and any other value is rejected with 400 DECLARATION_MODE_NOT_ALLOWED. A declaration that involves a counterparty is created through its own route (POST /v1/dd/bilateral/propose), which is where the counterparty is recorded.' operationId: postV1DdCreate x-operation-id-source: derived /v1/dd/confirm: post: tags: - DD summary: Confirm DD (after execution) security: - AgentToken: [] requestBody: required: true content: application/json: schema: type: object required: - dd_id properties: dd_id: type: string format: uuid example: dd_id: 00000000-0000-4000-8000-000000000000 responses: '200': description: 'DD confirmed. sync_reward appears only when a synchrony reward was actually credited: the record carried dd.decision_at, the feature is enabled, and the gap to the anchoring time fell inside the configured window. When no reward was credited the key is absent rather than null. The reward is credited in Earned DAC and is not part of cost_breakdown, which describes what was charged.' content: application/json: schema: type: object properties: dd_id: type: string format: uuid settlement_status: type: string anchored_at: type: string format: date-time integrity_hash: type: string dac_ur_recorded: type: boolean payment_sources: type: array items: type: string enum: - trial - external - earned description: Distinct sources that paid this record's rows (base fee and premium may differ). Not collapsed to one value. settlement_currency: type: - string - 'null' description: USDC when an external x402 payment settled the record. null when no external currency moved (Trial balance or Earned DAC covered it); the value is not a claim that anything settled on-chain. exchange_rate_timestamp: type: - string - 'null' format: date-time description: Set only when settlement_currency is set. sync_reward: type: object description: Present only when a reward was credited. properties: dac_amount: type: number description: Earned DAC credited. gap_seconds: type: integer description: anchored_at minus decision_at, in seconds. Derived, never stored. window_minutes: type: integer description: The window in force at the time of this confirmation. earned_balance: type: number description: Earned DAC balance after the credit. expires_at: type: string format: date-time description: When this credited lot expires. '403': description: 'FORBIDDEN: the record belongs to another agent.' content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: 'DD_NOT_FOUND: no record with this dd_id, or no payment row for it.' content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: 'ALREADY_CONFIRMED: the record is already settled. Confirmation happens once.' content: application/json: schema: $ref: '#/components/schemas/Error' '410': description: 'PAYMENT_EXPIRED: the external payment window has closed and the reservation was released. The record can no longer be confirmed and its usage entry will not be created. Does not apply to trial-covered records, which carry no reservation and no window.' content: application/json: schema: $ref: '#/components/schemas/Error' description: 'Confirm an anchored decision after the action it declared has been carried out. Every record is confirmed here, whatever paid its base fee (Trial balance, external x402 payment, or Earned DAC): confirmation moves the record to settled and writes its usage entry (DAC-UR). A record that is never confirmed stays unsettled and has no usage entry. When two agents declared, each side''s declaration is recorded externally. Each agent''s internal logs are self-testimony, only proving its own version. Decision Anchor''s external record resolves Self-testimony limits so both sides can verify, and each side''s declaration is recorded outside both platforms.' operationId: postV1DdConfirm x-operation-id-source: derived /v1/dd/list: get: tags: - DD summary: List DDs security: - AgentToken: [] parameters: - name: from in: query schema: type: string format: date-time - name: to in: query schema: type: string format: date-time - name: limit in: query schema: type: integer default: 50 - name: offset in: query schema: type: integer default: 0 responses: '200': description: DD list operationId: getV1DdList x-operation-id-source: derived /v1/dd/{dd_id}: get: tags: - DD summary: Get DD detail security: - AgentToken: [] parameters: - name: dd_id in: path required: true schema: type: string format: uuid responses: '200': description: DD detail. Every value the agent sent at creation is readable here, including the ones that entered the price (EE axes) and the integrity hash (dd fields, decision_at). content: application/json: schema: type: object properties: dd: type: object properties: dd_id: type: string format: uuid agent_id: type: string format: uuid dd_unit_type: type: string enum: - single - batch dd_declaration_mode: type: string enum: - self_declared - bilateral - multi_party decision_type: type: string enum: - internal_service - external_interaction - self_attestation decision_action_type: type: string enum: - execute - hold - reject - depend - approve origin_context_type: type: string enum: - internal - external - self - mixed selection_state: type: string enum: - SELECTED - REJECTED - ABORTED - SILENT - NON_DECISION selection_scope: type: - string - 'null' enum: - single_target - multi_target - chain_scope - global - null content_inclusion_flag: type: integer enum: - 0 - 1 decision_at: type: - string - 'null' format: date-time description: The stored, UTC-normalized value that entered integrity_hash; null when not declared. anchored_at: type: string format: date-time integrity_hash: type: string core_schema_version: type: string ee: type: - object - 'null' properties: ee_id: type: string format: uuid ee_retention_period: type: string ee_integrity_verification_level: type: string ee_disclosure_format_policy: type: string ee_responsibility_scope: type: string ee_direct_access_period: type: string ee_direct_access_quota: type: integer access_class: type: string enum: - self_direct - ara_only - internal_only content_disclosure_scope: type: string enum: - owner - external - public delegation_state: type: string enum: - none - partial - full dac: type: - object - 'null' properties: dac_amount: type: number dac_unit_type: type: string cost_context_type: type: string pricing_version: type: - string - 'null' payment: type: - object - 'null' properties: settlement_status: type: string description: unreserved (Trial-covered, not yet confirmed) | pending (external, awaiting confirm) | settled | released payment_sources: type: array items: type: string enum: - trial - external - earned payment_method: type: - string - 'null' description: Set only when external currency moved. paid_at: type: - string - 'null' format: date-time direct_access: type: - object - 'null' properties: access_class: type: string direct_access_remaining: type: integer direct_access_expires_at: type: string format: date-time operationId: getV1DdByDdId x-operation-id-source: derived /v1/dd/{dd_id}/lineage: get: tags: - DD summary: Get DD lineage security: - AgentToken: [] parameters: - name: dd_id in: path required: true schema: type: string format: uuid responses: '200': description: Lineage tree operationId: getV1DdByDdIdLineage x-operation-id-source: derived /v1/dd/lineage-group/{group_id}: get: tags: - DD summary: Get lineage group security: - AgentToken: [] parameters: - name: group_id in: path required: true schema: type: string format: uuid responses: '200': description: DDs in lineage group operationId: getV1DdLineageGroupByGroupId x-operation-id-source: derived components: schemas: CostBreakdown: type: object properties: base_fee: type: number base_fee_source: type: string premium: type: number premium_source: type: string subtotal: type: number description: Sum of base_fee and all EE axis adds, before the multiplier. subtotal x multiplier = total_dac. (base_fee + premium also equals total_dac; those two are the ledger split, not the multiplier split.) multiplier: type: number description: Conditional risk multiplier actually applied to this record. See multiplier_conditions in GET /v1/pricing/current for the threshold. total_dac: type: number Error: type: object required: - error_code - message properties: error_code: type: string message: type: string EEInput: type: object description: The four axis fields are required unless ee_preset is provided (a preset expands into all four). required: - ee_retention_period - ee_integrity_verification_level - ee_disclosure_format_policy - ee_responsibility_scope properties: ee_preset: type: string description: 'Optional EE preset name. Expands into the four required EE axes and overrides them when both are sent. The preset list is operator-managed; fetch active presets via GET /v1/pricing/ee-presets (currently EE_basic, EE_standard, EE_high). Unknown name: 400 INVALID_EE_PRESET; disabled: 400 EE_PRESET_DISABLED. Accepted on POST /v1/dd/create only; the bilateral propose path rejects this key (400 UNKNOWN_FIELD).' ee_retention_period: type: string enum: - short - medium - long - extreme_long - indefinite description: 'Retention selection. All five values are sent in this one field, but they are not one ladder. short, medium and long are the retention axis; their add is priced along the axis and long is one of the multiplier conditions. extreme_long (3,650 days / 10 years, 100 DAC one-time) and indefinite (permanent, no axis add) are overlay options that sit on top of the axis rather than extending it, so neither carries an axis value for the ''Retention = Long'' multiplier condition to match. indefinite is declared but not currently available: selecting it is rejected. Current adds and availability: GET /v1/pricing/current.' ee_integrity_verification_level: type: string enum: - basic - enhanced - certifiable ee_disclosure_format_policy: type: string enum: - internal - shareable - exportable ee_responsibility_scope: type: string enum: - minimal - standard - extended ee_direct_access_period: type: string pattern: ^[1-9]\d*[dmy]$ description: 'Optional: system default applied when omitted. Format like "30d", "12m", "1y" (d=days, m=months, y=years).' ee_direct_access_quota: type: integer minimum: 0 description: 'Optional: system default applied when omitted. Non-negative integer.' content_disclosure_scope: type: string enum: - owner - external - public default: owner description: Pricing axis, optional, defaults to owner. delegation_state: type: string enum: - none - partial - full default: none description: Pricing axis, optional, defaults to none. access_class: type: string enum: - self_direct - ara_only - internal_only description: Optional. DDInput: type: object required: - dd_unit_type - dd_declaration_mode - decision_type - decision_action_type - origin_context_type - selection_state properties: dd_unit_type: type: string enum: - single - batch description: 'How many decisions this record covers. single: one decision. batch: a set of decisions you declare as one unit.' dd_declaration_mode: type: string enum: - self_declared - bilateral - multi_party description: 'Who declares. self_declared: you alone (the only value POST /v1/dd/create accepts). bilateral: you and one counterparty, created through POST /v1/dd/bilateral/propose. multi_party: reserved; not accepted on either route.' decision_type: type: string enum: - internal_service - external_interaction - self_attestation description: 'What the decision concerns. internal_service: an operation inside your own platform or service. external_interaction: an exchange with a party or system outside it (a payment, a delegation, an agreement). self_attestation: a statement about your own state or intent rather than an action on anything else. DA records the value you send and does not check it.' decision_action_type: type: string enum: - execute - hold - reject - depend - approve description: 'What the decision did: execute (carried out), hold (kept pending), reject (declined), depend (deferred to another decision or party), approve (authorized something else to proceed).' origin_context_type: type: string enum: - internal - external - self - mixed description: 'What set the decision in motion. internal: your platform or orchestrator. external: an outside party or event. self: your own initiative. mixed: more than one of these. DA records the value you send and does not check it.' selection_state: type: string enum: - SELECTED - REJECTED - ABORTED - SILENT - NON_DECISION description: 'How the selection ended: SELECTED (a choice was made), REJECTED (the options were declined), ABORTED (the process stopped before a choice), SILENT (no response was given), NON_DECISION (the situation was left undecided on purpose). Every value is a valid declaration, including the ones where nothing was carried out.' selection_scope: type: string enum: - single_target - multi_target - chain_scope - global description: Optional. decision_at: type: string format: date-time description: 'Optional. The time the agent itself decided, as an ISO 8601 timestamp. The server normalizes it to UTC and stores the normalized value, which is also what enters integrity_hash; send it in any valid offset and read back the stored value with GET /v1/dd/{dd_id}. It must not be later than the anchoring time: a later value is rejected with 400 DECISION_AT_IN_FUTURE. Omit it and no decision time is recorded. The distance between decision_at and anchored_at is derived, never stored. When the time-alignment credit is enabled and that gap is within the configured window, Earned DAC is credited at confirm (confirm response sync_reward); current window, amount and whether it is enabled: GET /v1/pricing/current sync_reward.' parent_dd_id: type: string format: uuid TemplateInput: type: object minProperties: 1 description: 'Content Inclusion branch 1: 7-dimension decision metadata. Required when content_inclusion_flag=1; at least 1 of the 7 dimensions must be filled.' properties: decision_class: type: string enum: - payment - api_call - data_access - delegation - resource_transfer - communication - other decision_scale_value: type: number target_class: type: string enum: - internal - external - third_party - subagent - human_owner - public - system call_chain: type: array maxItems: 32 description: Tool identifier tokens only (no spaces, no free text). Entries containing personal identifying information are rejected. items: type: string pattern: ^[A-Za-z0-9][A-Za-z0-9_.:-]{0,63}$ decision_scale_unit: type: string maxLength: 20 pattern: ^[A-Za-z0-9][A-Za-z0-9_./%-]{0,19}$ description: Short unit code for decision_scale_value (e.g. "USDC", "USD"). No spaces, no free text. self_classification: type: string description: Key registered in the self-classification registry (GET /v1/classification). Unregistered keys are rejected. decision_trigger: type: string enum: - user_request - scheduled - event_driven - autonomous - delegated - external_event human_involvement: type: string enum: - none - notification - approval - co_decision - review X402Challenge: type: object description: x402 payment challenge envelope. Instance values (amount, payTo, extensions) are resolved per request at runtime and are intentionally not fixed here; read them from the live 402 response. properties: x402Version: type: integer enum: - 2 description: x402 protocol version. error: type: string description: Short reason string, e.g. "Payment required". resource: type: object description: The resource being paid for. properties: url: type: string format: uri description: type: string mimeType: type: string accepts: type: array description: Accepted payment options. Decision Anchor issues exactly one (exact scheme, USDC on Base). items: type: object properties: scheme: type: string description: Payment scheme. Decision Anchor uses "exact". network: type: string description: CAIP-2 chain id. Decision Anchor settles on Base (eip155:8453). amount: type: string description: Amount in the asset's smallest unit (USDC has 6 decimals). Computed per request from the EE axes, so it varies; always read it from the live challenge. asset: type: string description: ERC-20 contract address of the settlement asset (USDC on Base). payTo: type: string description: Recipient address. Operator-configured; read it from the live challenge rather than pinning it. maxTimeoutSeconds: type: integer description: Validity window of this challenge. extra: type: object description: 'Scheme-specific metadata (for exact/EIP-3009: the asset''s EIP-712 domain name and version).' additionalProperties: true extensions: type: object description: Optional discovery metadata attached by the x402 library (e.g. bazaar input/output schemas). Shape is library-defined and not pinned here. additionalProperties: true responses: PaymentRequired: description: 'Payment required: the response body and the `PAYMENT-REQUIRED` header both carry an x402 payment challenge (HTTP 402, x402 protocol v2). Obtain the challenge, produce a payment payload with your own wallet, and retry the identical request with a `Payment-Signature` header. Routes marked trial_eligible in /.well-known/x402.json are covered by the Trial balance while it lasts, in which case no challenge is issued.' headers: PAYMENT-REQUIRED: description: Base64-encoded x402 challenge (canonical source; the JSON body is a convenience copy). schema: type: string content: application/json: schema: $ref: '#/components/schemas/X402Challenge' securitySchemes: AgentToken: type: http scheme: bearer description: Agent auth_token issued at registration (POST /v1/agent/register). Send it in the Authorization header using the Bearer scheme, followed by the issued token value. DAPSession: type: apiKey in: cookie name: connect.sid description: Session cookie issued after DAP login externalDocs: description: 'Decision Anchor positioning & semantics for AI agents: why DA exists, Content-blind Accountability, Self-testimony Resolution, and when to use each mechanism. Read llms.txt for meaning and when-to-use, not just the endpoint contract.' url: https://api.decision-anchor.com/llms.txt