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

# Send a Salesforce record to CaseXchange as a new case or re-referral

> Turns an org-side "send this record to CaseXchange" submit into a durable, idempotent CaseXchange case creation (or re-referral to a new firm) — spec §7.2. Reads the source record from Salesforce using the firm's active, activated, interactive-send-enabled v2 sending profile, applies its confirmed prefill links plus any `overrides`, and creates (or re-refers) a case.

Idempotency: pass a fresh `idempotencyKey` (UUID) on every distinct submit. Replaying the same key returns the original outcome with `200` and `attempt.replay: true` instead of creating a duplicate case; a genuinely new submit must use a new key.

Observing write-back: there is NO status-check endpoint. Once this call returns, the CaseXchange case exists, but its bridge fields (match key, status, reference number, deep link) are stamped back onto the source Salesforce record asynchronously by the write-back job — observe completion by reading those fields on the source record (typically within ~5 minutes). A send that exhausts its write-back retries moves to `needs_attention` and is paused for an admin; that state sends NO signal to the org side, so clients should surface a send whose fields remain unstamped after a timeout as stale rather than wait indefinitely.

Error codes (409s carry a per-code `error.details` object — see the 409 response):
- `400 unsupported_match_key_mode` — the resolved sending profile does not use an external-ID match key (send is not supported).
- `400 validation_error` — the built create payload failed validation; `error.details.errors` carries the field-level issues.
- `400 bad_request` — a re-refer business-rule rejection propagated from the re-referral service (e.g. the case is not in a re-referable status, or no prior referral exists); the message is descriptive.
- `404 send_mapping_not_configured` — no active, activated, interactive-send-enabled v2 sending profile matches the given object/record type.
- `404 source_record_not_found` — sourceRecordId does not exist (or is not visible) in Salesforce.
- `404 linked_case_not_found` — reRefer was requested but no linked CaseXchange case exists for this record (or it no longer exists).
- `409 record_already_sent` — the record is already linked to a CaseXchange case and reRefer was not requested. `error.details`: `{ baseCaseId, referenceNumber }` (the existing case, so the client can offer re-refer).
- `409 record_already_linked` — the record already carries a match-key value from a prior send with no active link. `error.details`: `{ matchKeyValue }`.
- `409 send_in_progress` — a send for this record (or idempotency key) is already in flight. `error.details`: `{ retryAfterMs }` — the remaining in-flight window (floored at 0) to back off before retrying.
- `409 attempt_failed` — a previous send with this idempotency key failed; submit a fresh key to retry. `error.details`: `{ failureCode, lastError }`.
- `502 salesforce_unavailable` — no usable Salesforce access token for this connection.
- `502 salesforce_read_failed` — the Salesforce SOQL read of the source record failed.

Requires FULL tier.



## OpenAPI

````yaml /api-reference/openapi.yml post /salesforce/interactive-sends
openapi: 3.0.3
info:
  title: CaseXchange Public API
  version: 1.0.0
  description: >-
    The CaseXchange Public API enables law firms to integrate referral
    management

    directly into their own systems.


    ## Authentication

    All requests must include an `X-API-Key` header containing a valid API key

    (format: `cxp_<hex>`). Keys are scoped to a firm and an access tier.


    ## Access Tiers

    | Tier | Description |

    |------|-------------|

    | `read_only` | GET endpoints — read data without mutation |

    | `standard` | read_only + create/update case referrals |

    | `full` | standard + delete, routing rules, bulk import, firm mutation |


    ## Rate Limiting

    Rate limits are enforced per API key. Exceeded limits return `429 Too Many
    Requests`.


    ## Pagination

    List endpoints accept `page` (default 1) and `limit` (default 20, max 100)
    query params.


    ## Response Format

    Successful responses are wrapped in `{ data: T, meta: { requestId, timestamp
    } }`.

    Errors are wrapped in `{ error: { code, message }, meta: { requestId,
    timestamp } }`.
  contact:
    name: CaseXchange API Support
    url: https://casexchange.com
servers:
  - url: https://api.casexchange.com/api/public/v1
    description: Production Public API base path
  - url: /api/public/v1
    description: Relative base path (for proxied docs/local environments)
security: []
tags:
  - name: Reference Data
    description: Case types, jurisdictions, and counties
  - name: Firms
    description: Firm directory and profile management
  - name: Cases
    description: Case referral lifecycle and actions
  - name: Sent Cases
    description: 'Sender-side case management: create, track, and refer/route cases you own'
  - name: Documents
    description: Document upload, download, and management
  - name: Users
    description: User management within the caller's firm
  - name: Routing
    description: Referral routing rules
  - name: Analytics
    description: Dashboard and case analytics
  - name: Notifications
    description: Notification preferences and email management
  - name: Med Cases
    description: Med Xchange cases and their nested referrals to medical providers
  - name: MedEx Documents
    description: Med Xchange case document listing and download
  - name: Import
    description: Bulk case import/update via CSV
  - name: Salesforce
    description: Org-facing endpoints consumed by the CaseXchange managed package
paths:
  /salesforce/interactive-sends:
    post:
      tags:
        - Salesforce
      summary: Send a Salesforce record to CaseXchange as a new case or re-referral
      description: >-
        Turns an org-side "send this record to CaseXchange" submit into a
        durable, idempotent CaseXchange case creation (or re-referral to a new
        firm) — spec §7.2. Reads the source record from Salesforce using the
        firm's active, activated, interactive-send-enabled v2 sending profile,
        applies its confirmed prefill links plus any `overrides`, and creates
        (or re-refers) a case.


        Idempotency: pass a fresh `idempotencyKey` (UUID) on every distinct
        submit. Replaying the same key returns the original outcome with `200`
        and `attempt.replay: true` instead of creating a duplicate case; a
        genuinely new submit must use a new key.


        Observing write-back: there is NO status-check endpoint. Once this call
        returns, the CaseXchange case exists, but its bridge fields (match key,
        status, reference number, deep link) are stamped back onto the source
        Salesforce record asynchronously by the write-back job — observe
        completion by reading those fields on the source record (typically
        within ~5 minutes). A send that exhausts its write-back retries moves to
        `needs_attention` and is paused for an admin; that state sends NO signal
        to the org side, so clients should surface a send whose fields remain
        unstamped after a timeout as stale rather than wait indefinitely.


        Error codes (409s carry a per-code `error.details` object — see the 409
        response):

        - `400 unsupported_match_key_mode` — the resolved sending profile does
        not use an external-ID match key (send is not supported).

        - `400 validation_error` — the built create payload failed validation;
        `error.details.errors` carries the field-level issues.

        - `400 bad_request` — a re-refer business-rule rejection propagated from
        the re-referral service (e.g. the case is not in a re-referable status,
        or no prior referral exists); the message is descriptive.

        - `404 send_mapping_not_configured` — no active, activated,
        interactive-send-enabled v2 sending profile matches the given
        object/record type.

        - `404 source_record_not_found` — sourceRecordId does not exist (or is
        not visible) in Salesforce.

        - `404 linked_case_not_found` — reRefer was requested but no linked
        CaseXchange case exists for this record (or it no longer exists).

        - `409 record_already_sent` — the record is already linked to a
        CaseXchange case and reRefer was not requested. `error.details`: `{
        baseCaseId, referenceNumber }` (the existing case, so the client can
        offer re-refer).

        - `409 record_already_linked` — the record already carries a match-key
        value from a prior send with no active link. `error.details`: `{
        matchKeyValue }`.

        - `409 send_in_progress` — a send for this record (or idempotency key)
        is already in flight. `error.details`: `{ retryAfterMs }` — the
        remaining in-flight window (floored at 0) to back off before retrying.

        - `409 attempt_failed` — a previous send with this idempotency key
        failed; submit a fresh key to retry. `error.details`: `{ failureCode,
        lastError }`.

        - `502 salesforce_unavailable` — no usable Salesforce access token for
        this connection.

        - `502 salesforce_read_failed` — the Salesforce SOQL read of the source
        record failed.


        Requires FULL tier.
      operationId: createSalesforceInteractiveSend
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - sourceRecordId
                - sfObjectApiName
                - targetFirmIds
                - idempotencyKey
              properties:
                sourceRecordId:
                  type: string
                  pattern: ^[a-zA-Z0-9]{15,18}$
                  description: >-
                    Salesforce record Id (15 or 18 char) of the source record
                    being sent.
                sfObjectApiName:
                  type: string
                  description: Salesforce object API name, e.g. litify_pm__Matter__c.
                sfRecordTypeDevName:
                  type: string
                  nullable: true
                  description: >-
                    Record type developer name. Omit or null to match profiles
                    with no record type set.
                targetFirmIds:
                  type: array
                  items:
                    type: string
                    format: uuid
                  minItems: 1
                  maxItems: 1
                  description: >-
                    Receiving firm id(s) for this send. Array-shaped for forward
                    compatibility, but CaseXchange supports exactly one active
                    referral per case — exactly one target firm per send today.
                overrides:
                  type: object
                  additionalProperties:
                    nullable: true
                    oneOf:
                      - type: string
                      - type: number
                      - type: boolean
                  default: {}
                  description: >-
                    Optional per-field overrides keyed by casex.* canonical key.
                    Keys must be one of the interactive-send form fields
                    returned by GET /salesforce/send-mapping (sendFields).
                idempotencyKey:
                  type: string
                  format: uuid
                  description: >-
                    A fresh UUID generated by the caller for each distinct
                    submit. Replaying the same key returns the original outcome
                    (200, attempt.replay: true) instead of creating a duplicate
                    case.
                mappingVersion:
                  type: string
                  maxLength: 64
                  description: >-
                    Observability only, echoed from GET
                    /salesforce/send-mapping. A stale/mismatched value is logged
                    but never rejected — the server always re-reads current
                    mapping config.
                reRefer:
                  type: boolean
                  default: false
                  description: >-
                    When true and the source record is already linked to a
                    CaseXchange case, re-refer that case to targetFirmIds
                    instead of creating a new case.
                notes:
                  type: string
                  maxLength: 10000
                routingRuleId:
                  type: string
                  format: uuid
                  description: >-
                    Optional. Routing rule this send was chosen from (from GET
                    /routing/evaluate). Ignored (with a server-side warning) if
                    it is not a live rule owned by your firm.
                roundRobinPosition:
                  type: integer
                  minimum: 0
                  description: >-
                    Optional. The roundRobinPosition from GET /routing/evaluate.
                    Requires routingRuleId; advances the rule's round-robin
                    pointer.
      responses:
        '200':
          description: >-
            Replay of a previously processed idempotency key — returns the
            original outcome
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/InteractiveSendResult'
                  meta:
                    type: object
                    properties:
                      requestId:
                        type: string
                        example: req_f2dbe1d3f6ad4a7bb5b4c9f2
                      timestamp:
                        type: string
                        format: date-time
                    required:
                      - requestId
                      - timestamp
                required:
                  - data
                  - meta
        '201':
          description: New case created (or re-referred) from the source record
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/InteractiveSendResult'
                  meta:
                    type: object
                    properties:
                      requestId:
                        type: string
                        example: req_f2dbe1d3f6ad4a7bb5b4c9f2
                      timestamp:
                        type: string
                        format: date-time
                    required:
                      - requestId
                      - timestamp
                required:
                  - data
                  - meta
        '400':
          description: Request validation failed
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                    required:
                      - code
                      - message
                  meta:
                    type: object
                    properties:
                      requestId:
                        type: string
                        example: req_f2dbe1d3f6ad4a7bb5b4c9f2
                      timestamp:
                        type: string
                        format: date-time
                    required:
                      - requestId
                      - timestamp
                required:
                  - error
                  - meta
        '401':
          description: Invalid or missing API key
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                    required:
                      - code
                      - message
                  meta:
                    type: object
                    properties:
                      requestId:
                        type: string
                        example: req_f2dbe1d3f6ad4a7bb5b4c9f2
                      timestamp:
                        type: string
                        format: date-time
                    required:
                      - requestId
                      - timestamp
                required:
                  - error
                  - meta
        '403':
          description: API key tier does not permit this action
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                    required:
                      - code
                      - message
                  meta:
                    type: object
                    properties:
                      requestId:
                        type: string
                        example: req_f2dbe1d3f6ad4a7bb5b4c9f2
                      timestamp:
                        type: string
                        format: date-time
                    required:
                      - requestId
                      - timestamp
                required:
                  - error
                  - meta
        '404':
          description: Resource not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                    required:
                      - code
                      - message
                  meta:
                    type: object
                    properties:
                      requestId:
                        type: string
                        example: req_f2dbe1d3f6ad4a7bb5b4c9f2
                      timestamp:
                        type: string
                        format: date-time
                    required:
                      - requestId
                      - timestamp
                required:
                  - error
                  - meta
        '409':
          description: >-
            Conflict — the `error.code` selects one of four cases, each with a
            distinct `error.details` shape:

            - `record_already_sent` (already linked; pass reRefer to re-refer
            instead) — `details: { baseCaseId, referenceNumber }`.

            - `record_already_linked` (claimed by a prior send with no active
            link) — `details: { matchKeyValue }`.

            - `send_in_progress` (a send for this record/key is already in
            flight) — `details: { retryAfterMs }`, the remaining in-flight
            window in ms (floored at 0).

            - `attempt_failed` (the prior attempt for this idempotency key
            failed; use a fresh key) — `details: { failureCode, lastError }`.
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                    required:
                      - code
                      - message
                  meta:
                    type: object
                    properties:
                      requestId:
                        type: string
                        example: req_f2dbe1d3f6ad4a7bb5b4c9f2
                      timestamp:
                        type: string
                        format: date-time
                    required:
                      - requestId
                      - timestamp
                required:
                  - error
                  - meta
        '502':
          description: >-
            Salesforce unavailable (`salesforce_unavailable`) or the source
            record read failed (`salesforce_read_failed`).
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                    required:
                      - code
                      - message
                  meta:
                    type: object
                    properties:
                      requestId:
                        type: string
                        example: req_f2dbe1d3f6ad4a7bb5b4c9f2
                      timestamp:
                        type: string
                        format: date-time
                    required:
                      - requestId
                      - timestamp
                required:
                  - error
                  - meta
      security:
        - apiKeyAuth: []
components:
  schemas:
    InteractiveSendResult:
      type: object
      description: >-
        Result of a durable, idempotent interactive send/re-refer (spec §7.2).
        `attempt.state` tells the org client where write-back stands:
        'writeback_pending' means the bridge fields will be stamped by the
        writeback job; 'completed' means they already have been. 'superseded'
        (terminal, returned on replay) means a later re-refer superseded this
        attempt's referral, so nothing is left to stamp. There is no
        status-check endpoint: the only signal that write-back finished is the
        bridge fields appearing on the source Salesforce record (typically
        within ~5 minutes). A send that exhausts its retries becomes
        'needs_attention' and is paused for an admin WITHOUT signalling the org,
        so clients should treat a still-unstamped record after a timeout as
        stale rather than poll indefinitely.
      properties:
        attempt:
          type: object
          properties:
            id:
              type: string
              format: uuid
            state:
              type: string
              enum:
                - processing
                - writeback_pending
                - completed
                - needs_attention
                - superseded
                - failed
              description: Attempt lifecycle state.
            idempotencyKey:
              type: string
              format: uuid
            replay:
              type: boolean
              description: >-
                True when this response replays a previously processed
                idempotency key (a genuine retry of the same submit) rather than
                a freshly created send.
          required:
            - id
            - state
            - idempotencyKey
            - replay
        sentCase:
          $ref: '#/components/schemas/SentCase'
      required:
        - attempt
        - sentCase
    SentCase:
      type: object
      description: >-
        A case from the sender (owning firm) perspective, with all of its
        referrals.
      properties:
        id:
          type: string
          format: uuid
        referenceNumber:
          type: string
          nullable: true
          example: ABC-0001
        salesforceId:
          type: string
          nullable: true
        salesforceObjectType:
          type: string
          nullable: true
        title:
          type: string
          nullable: true
        description:
          type: string
          nullable: true
        caseType:
          type: string
          nullable: true
        jurisdiction:
          type: string
          nullable: true
        county:
          type: string
          nullable: true
        clientFirstName:
          type: string
          nullable: true
        clientLastName:
          type: string
          nullable: true
        clientEmail:
          type: string
          format: email
          nullable: true
        clientPhone:
          type: string
          nullable: true
        clientDateOfBirth:
          type: string
          format: date
          nullable: true
        incidentDate:
          type: string
          format: date
          nullable: true
        tier:
          type: integer
          nullable: true
        source:
          type: string
          nullable: true
        status:
          type: string
          description: CaseStatus enum value
        closingStatus:
          type: string
          nullable: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        referrals:
          type: array
          description: All referrals on this case, most recent first.
          items:
            type: object
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: Public API key (starts with cxp_). Required on every request.

````