{
  "openapi": "3.1.1",
  "info": {
    "title": "Relasight ingestion API \u2014 proposed contract",
    "version": "0.2.0-draft",
    "description": "Design contract, not an operational API. The .invalid server is intentional. No credentials can be issued in the POC. See integrations.html for normative ingestion semantics."
  },
  "servers": [
    {
      "url": "https://api.relasight.invalid/v1",
      "description": "Non-resolving documentation placeholder; replace only after a backend is provisioned."
    }
  ],
  "paths": {
    "/sources": {
      "post": {
        "summary": "Register a source",
        "description": "PROPOSED ONLY. Not served by the public POC. Required token permission: sources:write.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Register a source",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Source"
                }
              }
            }
          },
          "default": {
            "description": "Request failure; 401 unauthenticated, 403 forbidden, 404 inaccessible resource, 409 conflict, 422 validation, 429 throttled, or 5xx transient failure.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SourceInput"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            },
            "description": "Unique stable key for this logical mutation. Same payload on retries; retained for at least 7 days."
          }
        ]
      },
      "get": {
        "summary": "List sources",
        "description": "PROPOSED ONLY. Not served by the public POC. Required token permission: sources:read.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "List sources",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Source"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "items",
                    "next_cursor"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Request failure; 401 unauthenticated, 403 forbidden, 404 inaccessible resource, 409 conflict, 422 validation, 429 throttled, or 5xx transient failure.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          }
        ]
      }
    },
    "/ingestion/batches": {
      "post": {
        "summary": "Queue a source batch",
        "description": "PROPOSED ONLY. Not served by the public POC. Required token permission: ingestion:write.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "202": {
            "description": "Queue a source batch",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchAccepted"
                }
              }
            }
          },
          "default": {
            "description": "Request failure; 401 unauthenticated, 403 forbidden, 404 inaccessible resource, 409 conflict, 422 validation, 429 throttled, or 5xx transient failure.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Batch"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            },
            "description": "Unique stable key for this logical mutation. Same payload on retries; retained for at least 7 days."
          }
        ]
      }
    },
    "/ingestion/batches/{batch_id}": {
      "get": {
        "summary": "Read every item result",
        "description": "PROPOSED ONLY. Not served by the public POC. Required token permission: ingestion:read.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Read every item result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchResult"
                }
              }
            }
          },
          "default": {
            "description": "Request failure; 401 unauthenticated, 403 forbidden, 404 inaccessible resource, 409 conflict, 422 validation, 429 throttled, or 5xx transient failure.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "batch_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          }
        ]
      }
    },
    "/identity-links": {
      "post": {
        "summary": "Link two existing source identities",
        "description": "PROPOSED ONLY. Not served by the public POC. Required token permission: identity:write.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Link two existing source identities",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdentityResult"
                }
              }
            }
          },
          "default": {
            "description": "Request failure; 401 unauthenticated, 403 forbidden, 404 inaccessible resource, 409 conflict, 422 validation, 429 throttled, or 5xx transient failure.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IdentityLink"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            },
            "description": "Unique stable key for this logical mutation. Same payload on retries; retained for at least 7 days."
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Proposed workspace-scoped service token, optionally restricted to source IDs. Never put tokens in browser code."
      }
    },
    "schemas": {
      "SourceInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "kind": {
            "type": "string",
            "enum": [
              "warehouse",
              "crm",
              "support",
              "billing",
              "other"
            ]
          }
        },
        "required": [
          "name",
          "kind"
        ]
      },
      "Source": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "kind": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "pattern": "Z$"
          }
        },
        "required": [
          "id",
          "name",
          "kind",
          "created_at"
        ]
      },
      "CustomerFields": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 160
          },
          "type": {
            "type": "string",
            "enum": [
              "company",
              "person"
            ]
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "format": "email"
          },
          "industry": {
            "type": [
              "string",
              "null"
            ]
          },
          "owner": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "name",
          "type"
        ]
      },
      "Observation": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "attribute": {
            "type": "string",
            "enum": [
              "interest",
              "renewal_date",
              "relationship_health",
              "note",
              "preference"
            ]
          },
          "value": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2000
          },
          "effective_at": {
            "type": "string",
            "format": "date-time",
            "pattern": "Z$"
          },
          "confidence": {
            "type": "string",
            "enum": [
              "Reported",
              "Verified",
              "Hypothesis"
            ]
          },
          "context": {
            "type": "string",
            "maxLength": 2000
          }
        },
        "required": [
          "attribute",
          "value",
          "effective_at",
          "confidence"
        ],
        "allOf": [
          {
            "if": {
              "properties": {
                "attribute": {
                  "const": "renewal_date"
                }
              }
            },
            "then": {
              "properties": {
                "value": {
                  "type": "string",
                  "format": "date"
                }
              }
            }
          }
        ]
      },
      "Item": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "operation": {
            "type": "string",
            "enum": [
              "customer.upsert",
              "observation.upsert",
              "observation.retract",
              "customer.unlink"
            ]
          },
          "external_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "source_version": {
            "type": "integer",
            "minimum": 1
          },
          "source_updated_at": {
            "type": "string",
            "format": "date-time",
            "pattern": "Z$"
          },
          "customer_external_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "customer": {
            "$ref": "#/components/schemas/CustomerFields"
          },
          "observation": {
            "$ref": "#/components/schemas/Observation"
          }
        },
        "required": [
          "operation",
          "external_id",
          "source_version",
          "source_updated_at"
        ],
        "allOf": [
          {
            "if": {
              "properties": {
                "operation": {
                  "const": "customer.upsert"
                }
              }
            },
            "then": {
              "required": [
                "customer"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "operation": {
                  "const": "observation.upsert"
                }
              }
            },
            "then": {
              "required": [
                "customer_external_id",
                "observation"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "operation": {
                  "const": "customer.upsert"
                }
              }
            },
            "then": {
              "properties": {
                "observation": false,
                "customer_external_id": false
              }
            }
          },
          {
            "if": {
              "properties": {
                "operation": {
                  "const": "observation.upsert"
                }
              }
            },
            "then": {
              "properties": {
                "customer": false
              }
            }
          },
          {
            "if": {
              "properties": {
                "operation": {
                  "const": "observation.retract"
                }
              }
            },
            "then": {
              "properties": {
                "customer": false,
                "observation": false,
                "customer_external_id": false
              }
            }
          },
          {
            "if": {
              "properties": {
                "operation": {
                  "const": "customer.unlink"
                }
              }
            },
            "then": {
              "properties": {
                "customer": false,
                "observation": false,
                "customer_external_id": false
              }
            }
          }
        ]
      },
      "Batch": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "source_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 500,
            "items": {
              "$ref": "#/components/schemas/Item"
            }
          }
        },
        "required": [
          "source_id",
          "items"
        ]
      },
      "BatchAccepted": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "status": {
            "type": "string",
            "const": "queued"
          },
          "status_url": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "status",
          "status_url"
        ]
      },
      "ItemResult": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "index": {
            "type": "integer",
            "minimum": 0
          },
          "external_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "status": {
            "type": "string",
            "enum": [
              "applied",
              "duplicate",
              "stale",
              "rejected"
            ]
          },
          "code": {
            "type": "string"
          },
          "detail": {
            "type": "string"
          },
          "customer_id": {
            "type": "string"
          }
        },
        "required": [
          "index",
          "external_id",
          "status"
        ]
      },
      "BatchResult": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "processing",
              "completed",
              "completed_with_errors",
              "failed"
            ]
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ItemResult"
            }
          }
        },
        "required": [
          "id",
          "status",
          "results"
        ]
      },
      "IdentityLink": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "left": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "source_id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              },
              "external_id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              }
            },
            "required": [
              "source_id",
              "external_id"
            ]
          },
          "right": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "source_id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              },
              "external_id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              }
            },
            "required": [
              "source_id",
              "external_id"
            ]
          },
          "reason": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1000
          }
        },
        "required": [
          "left",
          "right",
          "reason"
        ]
      },
      "IdentityResult": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "customer_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "aliases": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "source_id": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                "external_id": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              },
              "required": [
                "source_id",
                "external_id"
              ]
            }
          }
        },
        "required": [
          "customer_id",
          "aliases"
        ]
      },
      "Problem": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "instance": {
            "type": "string"
          },
          "request_id": {
            "type": "string"
          }
        },
        "required": [
          "type",
          "title",
          "status",
          "detail",
          "request_id"
        ]
      }
    }
  }
}
