> ## Documentation Index
> Fetch the complete documentation index at: https://docs.enfinitos.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Propose an offer

> Propose a new offer to derive a sub-right from one of the caller's existing rights. The parent right must be ACTIVE and the offered scope must be within the parent right's scope. Enters PROPOSED state and emits an `OFFER_PROPOSED` event. Requires scope `offers:write`.



## OpenAPI

````yaml /openapi-v1.yaml post /v1/offers/propose
openapi: 3.1.0
info:
  title: EnfinitOS API
  version: v1.0
  description: >-
    The governed-execution `/v1` developer API for EnfinitOS — rights, delivery,
    proof, and settlement.


    Use this API to register the legal **bases** a right rests on, **issue** and
    lifecycle-manage rights across delivery substrates (DOOH, CTV, spatial/AR,
    mobile, audio, and more), negotiate **offers**, raise and resolve
    **challenges**, observe constraint-gated **deliveries**, seal signed **proof
    packs**, read **metering** + **settlement** projections, configure
    settlement **rules** and **counterparties**, fulfil GDPR **compliance**
    requests, and subscribe to **webhooks**.


    Every state-changing action is appended to an immutable, signable audit log;
    delivery and proof artefacts are Ed25519-signed so a downstream auditor can
    verify them offline.


    ## Response envelope

    Every response wraps its payload in a canonical envelope.


    Success (HTTP 200):

    ```json { "ok": true, "data": { ... }, "contractVersion": "v1.0" } ```


    Error (4xx / 5xx):

    ```json { "ok": false, "error": "VALIDATION_FAILED", "message": "human
    text", "contractVersion": "v1.0" } ```

    Some error responses carry additional context fields alongside `error` and
    `message` (for example `field`, `validationErrors`, `requiredScopes`,
    `keyScopes`).


    ## Authentication

    All endpoints except `GET /v1` and `GET /v1/healthz` require an API key sent
    as `Authorization: Bearer <api-key>`. Keys carry a set of named scopes; each
    operation documents the scope it requires. A key carrying the `*` wildcard
    scope passes every scope check.

    Pre-launch, sandbox keys are issued through the apply flow: request access
    at `/apply`, receive an activation email on approval, and exchange it for a
    `/v1` sandbox key in the integration playground at `/developers/playground`.
    Self-service key issuance from the developer dashboard at
    `/developers/dashboard` lands at the April 2027 production launch.


    ## Identifiers

    Resource ids are prefixed: bases `bas_…`, rights `rgh_…`, offers `ofr_…`
    (passed as `rightId`/`offerId`), settlement rules `rule_…`, counterparties
    `cp_…`, webhook subscriptions, and webhook deliveries `dlv_…`. All
    timestamps are ISO-8601 strings.
  contact:
    name: EnfinitOS Developer Support
    url: https://docs.enfinitos.com
    email: developers@enfinitos.com
servers:
  - url: https://sandbox.api.enfinitos.com
    description: Sandbox — live today
  - url: https://api.enfinitos.com
    description: Production — at the April 2027 launch
security:
  - bearerAuth: []
tags:
  - name: Discovery
    description: Unauthenticated contract + health probes.
  - name: Tenant
    description: Read the caller's sandbox tenant snapshot.
  - name: Rights
    description: Bases and the right lifecycle (issue, suspend, resume, revoke).
  - name: Offers
    description: Propose, accept, reject, counter, and withdraw offers.
  - name: Challenges
    description: Open, resolve, and withdraw challenges against rights.
  - name: Delivery
    description: Observe constraint-gated delivery events.
  - name: Audit
    description: The append-only event log.
  - name: Proof
    description: Signed proof packs.
  - name: Metering & Settlement
    description: Metering and settlement projections.
  - name: Settlement config
    description: Settlement rules and counterparties.
  - name: Compliance
    description: GDPR Article 15 export and Article 17 erasure.
  - name: Webhooks
    description: Webhook subscriptions and delivery history.
  - name: Disputes
    description: Delivery disputes — open, investigate, respond, resolve.
paths:
  /v1/offers/propose:
    post:
      tags:
        - Offers
      summary: Propose an offer
      description: >-
        Propose a new offer to derive a sub-right from one of the caller's
        existing rights. The parent right must be ACTIVE and the offered scope
        must be within the parent right's scope. Enters PROPOSED state and emits
        an `OFFER_PROPOSED` event. Requires scope `offers:write`.
      operationId: proposeOffer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - rightId
                - toOrgId
                - scope
              properties:
                rightId:
                  type: string
                  description: Parent right to draw scope from (prefixed `rgh_`).
                  example: rgh_3a91f8c20b6d4e75
                toOrgId:
                  type: string
                  description: The counter-party org id.
                scope:
                  type: string
                  minLength: 1
                  description: >-
                    Sub-scope being offered; must be within the parent right's
                    scope.
                termsRef:
                  type:
                    - string
                    - 'null'
                  description: Optional reference to off-chain commercial terms.
                expiresAt:
                  type: string
                  format: date-time
                  description: >-
                    Optional; must be in the future. Defaults to 7 days from
                    now.
      responses:
        '200':
          description: The proposed offer.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OfferResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/StateConflict'
        '412':
          $ref: '#/components/responses/PreconditionFailed'
        '422':
          $ref: '#/components/responses/ValidationFailed'
components:
  schemas:
    OfferResponse:
      allOf:
        - $ref: '#/components/schemas/SuccessEnvelope'
        - type: object
          properties:
            data:
              type: object
              properties:
                offer:
                  $ref: '#/components/schemas/Offer'
    SuccessEnvelope:
      type: object
      required:
        - ok
        - data
        - contractVersion
      properties:
        ok:
          type: boolean
          const: true
        data:
          description: Route-specific payload. Operation responses refine this.
          type: object
        contractVersion:
          type: string
          const: v1.0
    Offer:
      type: object
      properties:
        id:
          type: string
        fromOrgId:
          type: string
        toOrgId:
          type: string
        rightId:
          type: string
        scope:
          type: string
          description: Sub-scope being offered; must be within the parent right's scope.
        termsRef:
          type:
            - string
            - 'null'
        status:
          $ref: '#/components/schemas/OfferStatus'
        expiresAt:
          type: string
          format: date-time
        derivedRightId:
          type:
            - string
            - 'null'
          description: Set when accepted — the derived right id.
        contentHash:
          type: string
          description: SHA-256 over canonical-sorted fields, `sha256:`-prefixed.
        createdAt:
          type: string
          format: date-time
    ErrorEnvelope:
      type: object
      required:
        - ok
        - error
        - message
      properties:
        ok:
          type: boolean
          const: false
        error:
          $ref: '#/components/schemas/ErrorCode'
        message:
          type: string
          description: Human-readable explanation.
        contractVersion:
          type: string
          const: v1.0
        field:
          type: string
          description: Present on some VALIDATION_FAILED errors — the offending field.
        validationErrors:
          type: array
          description: Present on settlement-rule / counterparty validation failures.
          items:
            type: object
            additionalProperties: true
        requiredScopes:
          type: array
          description: Present on SCOPE_MISSING — the scopes the operation needs.
          items:
            type: string
        keyScopes:
          type: array
          description: Present on SCOPE_MISSING — the scopes the presented key carries.
          items:
            type: string
      additionalProperties: true
    OfferStatus:
      type: string
      enum:
        - PROPOSED
        - ACCEPTED
        - REJECTED
        - COUNTERED
        - WITHDRAWN
        - EXPIRED
    ErrorCode:
      type: string
      description: Machine-readable error code. Drives the HTTP status.
      enum:
        - AUTH_REQUIRED
        - AUTH_INVALID
        - SCOPE_MISSING
        - BAD_REQUEST
        - VALIDATION_FAILED
        - RESOURCE_NOT_FOUND
        - STATE_CONFLICT
        - PRECONDITION_FAILED
        - RATE_LIMITED
        - INTERNAL_ERROR
  responses:
    Unauthorized:
      description: >-
        Missing/malformed Authorization header (AUTH_REQUIRED) or an invalid key
        (AUTH_INVALID).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    Forbidden:
      description: >-
        The key is valid but missing one or more required scopes
        (SCOPE_MISSING).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    NotFound:
      description: >-
        The referenced resource does not exist in this tenant
        (RESOURCE_NOT_FOUND).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    StateConflict:
      description: >-
        The resource is in a state that forbids this transition, or a concurrent
        write lost (STATE_CONFLICT).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    PreconditionFailed:
      description: >-
        A precondition failed — a constraint violation or a missing confirmation
        token (PRECONDITION_FAILED).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    ValidationFailed:
      description: >-
        A field was missing or wrong-typed (VALIDATION_FAILED). May carry
        `field` or `validationErrors`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: 'API key sent as `Authorization: Bearer <api-key>`.'

````