{
  "openapi": "3.1.1",
  "info": {
    "title": "Samesake API",
    "description": "Send your systems' records of people to Samesake, which matches them to find the same person across your systems.\n\nEach API key belongs to one **source**: one of your systems, such as your CRM. Every call acts on that source's records only. Send the key in the `X-Api-Key` header.\n\nKeep Samesake up to date as your records change: create or update a record whenever it changes, and delete it when it's deleted. If your system can't tell you about deletions, send a complete list from time to time as a **snapshot**: records missing from it are deleted.\n\nErrors are problem details ([RFC 9457](https://www.rfc-editor.org/rfc/rfc9457)), with the content type `application/problem+json`. Each key can make up to 600 requests a minute.",
    "termsOfService": "https://samesake.co.uk/terms/",
    "contact": {
      "name": "Samesake",
      "url": "https://samesake.co.uk/",
      "email": "hello@samesake.co.uk"
    },
    "version": "v1"
  },
  "servers": [
    {
      "url": "https://app.samesake.co.uk"
    }
  ],
  "paths": {
    "/api/v1/records": {
      "post": {
        "tags": [
          "Records"
        ],
        "summary": "Create or update a record",
        "description": "Sends one record. If the source has no record with this `sourceRecordId`, it's created (201); if it has, that record is updated (200). Matching follows in the background.",
        "operationId": "UpsertRecord",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecordInput"
              },
              "example": {
                "sourceRecordId": "CRM-10042",
                "title": "Ms",
                "firstName": "Priya",
                "lastName": "Sharma",
                "email": "priya.sharma@example.com",
                "dateOfBirth": "1986-04-03",
                "addressLine1": "14 Larch Grove",
                "addressLine2": "Manchester",
                "postcode": "M20 6RT",
                "phones": [
                  "07700 900123",
                  "0161 496 0123"
                ]
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Updated, or unchanged if the record already had these details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecordIdResponse"
                },
                "example": {
                  "recordId": "rec_7k2m9xq4ht3b"
                }
              }
            }
          },
          "201": {
            "description": "Created: the source had no record with this ID.",
            "headers": {
              "Location": {
                "description": "Where to get the new record: /api/v1/records/{recordId}.",
                "schema": {
                  "type": "string"
                },
                "example": "/api/v1/records/rec_7k2m9xq4ht3b"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecordIdResponse"
                },
                "example": {
                  "recordId": "rec_7k2m9xq4ht3b"
                }
              }
            }
          },
          "400": {
            "description": "The request isn't valid. When a field breaks a limit, `errors` names the field and says why. A body that isn't JSON of the right shape gets this status without `errors`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
                  "title": "One or more validation errors occurred.",
                  "status": 400,
                  "errors": {
                    "sourceRecordId": [
                      "sourceRecordId is required."
                    ]
                  },
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "401": {
            "description": "The `X-Api-Key` header is missing, or the key isn't valid: it may have been revoked.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.2",
                  "title": "Unauthorized",
                  "status": 401,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "409": {
            "description": "Another request changed the same record at the same time. Retry the request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.10",
                  "title": "The record was changed by another request at the same time. Retry the request.",
                  "status": 409,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "413": {
            "description": "The request body is too large: at most 64 KB for one record, 8 MB for a batch or a snapshot's records.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.14",
                  "title": "Request body is too large.",
                  "status": 413,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "415": {
            "description": "The body isn't sent as JSON: set the `Content-Type` header to `application/json`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.16",
                  "title": "Unsupported Media Type",
                  "status": 415,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests with this key: at most 600 a minute. Wait the number of seconds in the `Retry-After` header (up to 60), then retry.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait, up to 60.",
                "schema": {
                  "type": "integer"
                },
                "example": 60
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "title": "Too Many Requests",
                  "status": 429,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      }
    },
    "/api/v1/records/batch": {
      "post": {
        "tags": [
          "Records"
        ],
        "summary": "Create or update records in a batch",
        "description": "Sends up to 1,000 records at once, each created or updated as by **Create or update a record**. The batch is all or nothing: if any record isn't valid, none is saved, and `errors` names each one by its position (`[2].email`). The results are in the order the records were sent.",
        "operationId": "UpsertRecords",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "maxItems": 1000,
                "minItems": 1,
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/RecordInput"
                }
              },
              "example": [
                {
                  "sourceRecordId": "CRM-10042",
                  "firstName": "Priya",
                  "lastName": "Sharma",
                  "email": "priya.sharma@example.com",
                  "phones": [
                    "07700 900123"
                  ]
                },
                {
                  "sourceRecordId": "CRM-10043",
                  "title": "Mr",
                  "firstName": "Tom",
                  "lastName": "Fletcher",
                  "dateOfBirth": "12/09/1979",
                  "postcode": "M1 4BT",
                  "phones": [
                    "07700 900456"
                  ]
                }
              ]
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "What happened to each record, in the order they were sent.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/UpsertResult"
                  }
                },
                "example": [
                  {
                    "sourceRecordId": "CRM-10042",
                    "recordId": "rec_7k2m9xq4ht3b",
                    "outcome": "Created"
                  },
                  {
                    "sourceRecordId": "CRM-10043",
                    "recordId": "rec_3n8p2w6c9r4d",
                    "outcome": "Updated"
                  }
                ]
              }
            }
          },
          "400": {
            "description": "The request isn't valid. When a field breaks a limit, `errors` names the field and says why. A body that isn't JSON of the right shape gets this status without `errors`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
                  "title": "One or more validation errors occurred.",
                  "status": 400,
                  "errors": {
                    "[1].email": [
                      "email must be at most 200 characters."
                    ]
                  },
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "401": {
            "description": "The `X-Api-Key` header is missing, or the key isn't valid: it may have been revoked.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.2",
                  "title": "Unauthorized",
                  "status": 401,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "409": {
            "description": "Another request changed the same record at the same time. Retry the request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.10",
                  "title": "The record was changed by another request at the same time. Retry the request.",
                  "status": 409,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "413": {
            "description": "The request body is too large: at most 64 KB for one record, 8 MB for a batch or a snapshot's records.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.14",
                  "title": "Request body is too large.",
                  "status": 413,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "415": {
            "description": "The body isn't sent as JSON: set the `Content-Type` header to `application/json`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.16",
                  "title": "Unsupported Media Type",
                  "status": 415,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests with this key: at most 600 a minute. Wait the number of seconds in the `Retry-After` header (up to 60), then retry.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait, up to 60.",
                "schema": {
                  "type": "integer"
                },
                "example": 60
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "title": "Too Many Requests",
                  "status": 429,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      }
    },
    "/api/v1/records/{recordId}": {
      "put": {
        "tags": [
          "Records"
        ],
        "summary": "Replace a record",
        "description": "Replaces every field of one of the source's records with the fields sent: a field left out or sent as null is cleared. `sourceRecordId` in the body is ignored, because the path names the record. Replacing a deleted record restores it.",
        "operationId": "ReplaceRecord",
        "parameters": [
          {
            "name": "recordId",
            "in": "path",
            "description": "Samesake's ID for the record, returned when it was created.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "rec_7k2m9xq4ht3b"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecordReplacement"
              },
              "example": {
                "title": "Ms",
                "firstName": "Priya",
                "lastName": "Sharma",
                "email": "p.sharma@example.com",
                "dateOfBirth": "1986-04-03",
                "addressLine1": "3 Willow Court",
                "addressLine2": "Stockport",
                "postcode": "SK4 2DD",
                "phones": [
                  "07700 900123"
                ]
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Replaced.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecordIdResponse"
                },
                "example": {
                  "recordId": "rec_7k2m9xq4ht3b"
                }
              }
            }
          },
          "400": {
            "description": "The request isn't valid. When a field breaks a limit, `errors` names the field and says why. A body that isn't JSON of the right shape gets this status without `errors`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
                  "title": "One or more validation errors occurred.",
                  "status": 400,
                  "errors": {
                    "phones": [
                      "At most 10 phone numbers are allowed."
                    ]
                  },
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "401": {
            "description": "The `X-Api-Key` header is missing, or the key isn't valid: it may have been revoked.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.2",
                  "title": "Unauthorized",
                  "status": 401,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "404": {
            "description": "The source has no record with this ID.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
                  "title": "Record not found.",
                  "status": 404,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "409": {
            "description": "Another request changed the same record at the same time. Retry the request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.10",
                  "title": "The record was changed by another request at the same time. Retry the request.",
                  "status": 409,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "413": {
            "description": "The request body is too large: at most 64 KB for one record, 8 MB for a batch or a snapshot's records.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.14",
                  "title": "Request body is too large.",
                  "status": 413,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "415": {
            "description": "The body isn't sent as JSON: set the `Content-Type` header to `application/json`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.16",
                  "title": "Unsupported Media Type",
                  "status": 415,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests with this key: at most 600 a minute. Wait the number of seconds in the `Retry-After` header (up to 60), then retry.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait, up to 60.",
                "schema": {
                  "type": "integer"
                },
                "example": 60
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "title": "Too Many Requests",
                  "status": 429,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      },
      "delete": {
        "tags": [
          "Records"
        ],
        "summary": "Delete a record",
        "description": "Deletes one of the source's records. Its details are removed from Samesake straight away; its IDs and its history stay. Deleting a record that's already deleted succeeds. Sending the record again later restores it.",
        "operationId": "DeleteRecord",
        "parameters": [
          {
            "name": "recordId",
            "in": "path",
            "description": "Samesake's ID for the record, returned when it was created.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "rec_7k2m9xq4ht3b"
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "The `X-Api-Key` header is missing, or the key isn't valid: it may have been revoked.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.2",
                  "title": "Unauthorized",
                  "status": 401,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "404": {
            "description": "The source has no record with this ID.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
                  "title": "Record not found.",
                  "status": 404,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "409": {
            "description": "Another request changed the same record at the same time. Retry the request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.10",
                  "title": "The record was changed by another request at the same time. Retry the request.",
                  "status": 409,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests with this key: at most 600 a minute. Wait the number of seconds in the `Retry-After` header (up to 60), then retry.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait, up to 60.",
                "schema": {
                  "type": "integer"
                },
                "example": 60
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "title": "Too Many Requests",
                  "status": 429,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      },
      "get": {
        "tags": [
          "Records"
        ],
        "summary": "Get a record",
        "description": "Returns one of the source's records as Samesake holds it, with the person it belongs to and the IDs (not the details) of the records matched to it from any source. A deleted record is still returned, with `deleted: true` and its details cleared.",
        "operationId": "GetRecord",
        "parameters": [
          {
            "name": "recordId",
            "in": "path",
            "description": "Samesake's ID for the record, returned when it was created.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "rec_7k2m9xq4ht3b"
          }
        ],
        "responses": {
          "200": {
            "description": "The record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecordView"
                },
                "example": {
                  "recordId": "rec_7k2m9xq4ht3b",
                  "sourceSystemCode": "CRM",
                  "sourceRecordId": "CRM-10042",
                  "title": "Ms",
                  "firstName": "Priya",
                  "lastName": "Sharma",
                  "email": "priya.sharma@example.com",
                  "dateOfBirth": "1986-04-03",
                  "addressLine1": "14 Larch Grove",
                  "addressLine2": "Manchester",
                  "postcode": "M20 6RT",
                  "phones": [
                    "07700 900123",
                    "0161 496 0123"
                  ],
                  "personId": "per_5d9h2k7m3x8q",
                  "deleted": false,
                  "linkedRecords": [
                    {
                      "recordId": "rec_3n8p2w6c9r4d",
                      "sourceSystemCode": "SHOP",
                      "sourceRecordId": "C-58210",
                      "linkType": "Auto"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "The `X-Api-Key` header is missing, or the key isn't valid: it may have been revoked.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.2",
                  "title": "Unauthorized",
                  "status": 401,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "404": {
            "description": "The source has no record with this ID.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
                  "title": "Record not found.",
                  "status": 404,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests with this key: at most 600 a minute. Wait the number of seconds in the `Retry-After` header (up to 60), then retry.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait, up to 60.",
                "schema": {
                  "type": "integer"
                },
                "example": 60
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "title": "Too Many Requests",
                  "status": 429,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      }
    },
    "/api/v1/records/by-source-id/{sourceRecordId}": {
      "put": {
        "tags": [
          "Records"
        ],
        "summary": "Replace a record by your ID",
        "description": "Replaces every field of one of the source's records with the fields sent: a field left out or sent as null is cleared. `sourceRecordId` in the body is ignored, because the path names the record. Replacing a deleted record restores it.",
        "operationId": "ReplaceRecordBySourceId",
        "parameters": [
          {
            "name": "sourceRecordId",
            "in": "path",
            "description": "Your ID for the record in this source.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "CRM-10042"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecordReplacement"
              },
              "example": {
                "title": "Ms",
                "firstName": "Priya",
                "lastName": "Sharma",
                "email": "p.sharma@example.com",
                "dateOfBirth": "1986-04-03",
                "addressLine1": "3 Willow Court",
                "addressLine2": "Stockport",
                "postcode": "SK4 2DD",
                "phones": [
                  "07700 900123"
                ]
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Replaced.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecordIdResponse"
                },
                "example": {
                  "recordId": "rec_7k2m9xq4ht3b"
                }
              }
            }
          },
          "400": {
            "description": "The request isn't valid. When a field breaks a limit, `errors` names the field and says why. A body that isn't JSON of the right shape gets this status without `errors`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
                  "title": "One or more validation errors occurred.",
                  "status": 400,
                  "errors": {
                    "phones": [
                      "At most 10 phone numbers are allowed."
                    ]
                  },
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "401": {
            "description": "The `X-Api-Key` header is missing, or the key isn't valid: it may have been revoked.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.2",
                  "title": "Unauthorized",
                  "status": 401,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "404": {
            "description": "The source has no record with this ID.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
                  "title": "Record not found.",
                  "status": 404,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "409": {
            "description": "Another request changed the same record at the same time. Retry the request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.10",
                  "title": "The record was changed by another request at the same time. Retry the request.",
                  "status": 409,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "413": {
            "description": "The request body is too large: at most 64 KB for one record, 8 MB for a batch or a snapshot's records.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.14",
                  "title": "Request body is too large.",
                  "status": 413,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "415": {
            "description": "The body isn't sent as JSON: set the `Content-Type` header to `application/json`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.16",
                  "title": "Unsupported Media Type",
                  "status": 415,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests with this key: at most 600 a minute. Wait the number of seconds in the `Retry-After` header (up to 60), then retry.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait, up to 60.",
                "schema": {
                  "type": "integer"
                },
                "example": 60
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "title": "Too Many Requests",
                  "status": 429,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      },
      "delete": {
        "tags": [
          "Records"
        ],
        "summary": "Delete a record by your ID",
        "description": "Deletes one of the source's records. Its details are removed from Samesake straight away; its IDs and its history stay. Deleting a record that's already deleted succeeds. Sending the record again later restores it.",
        "operationId": "DeleteRecordBySourceId",
        "parameters": [
          {
            "name": "sourceRecordId",
            "in": "path",
            "description": "Your ID for the record in this source.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "CRM-10042"
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "The `X-Api-Key` header is missing, or the key isn't valid: it may have been revoked.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.2",
                  "title": "Unauthorized",
                  "status": 401,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "404": {
            "description": "The source has no record with this ID.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
                  "title": "Record not found.",
                  "status": 404,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "409": {
            "description": "Another request changed the same record at the same time. Retry the request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.10",
                  "title": "The record was changed by another request at the same time. Retry the request.",
                  "status": 409,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests with this key: at most 600 a minute. Wait the number of seconds in the `Retry-After` header (up to 60), then retry.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait, up to 60.",
                "schema": {
                  "type": "integer"
                },
                "example": 60
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "title": "Too Many Requests",
                  "status": 429,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      },
      "get": {
        "tags": [
          "Records"
        ],
        "summary": "Get a record by your ID",
        "description": "Returns one of the source's records as Samesake holds it, with the person it belongs to and the IDs (not the details) of the records matched to it from any source. A deleted record is still returned, with `deleted: true` and its details cleared.",
        "operationId": "GetRecordBySourceId",
        "parameters": [
          {
            "name": "sourceRecordId",
            "in": "path",
            "description": "Your ID for the record in this source.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "CRM-10042"
          }
        ],
        "responses": {
          "200": {
            "description": "The record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecordView"
                },
                "example": {
                  "recordId": "rec_7k2m9xq4ht3b",
                  "sourceSystemCode": "CRM",
                  "sourceRecordId": "CRM-10042",
                  "title": "Ms",
                  "firstName": "Priya",
                  "lastName": "Sharma",
                  "email": "priya.sharma@example.com",
                  "dateOfBirth": "1986-04-03",
                  "addressLine1": "14 Larch Grove",
                  "addressLine2": "Manchester",
                  "postcode": "M20 6RT",
                  "phones": [
                    "07700 900123",
                    "0161 496 0123"
                  ],
                  "personId": "per_5d9h2k7m3x8q",
                  "deleted": false,
                  "linkedRecords": [
                    {
                      "recordId": "rec_3n8p2w6c9r4d",
                      "sourceSystemCode": "SHOP",
                      "sourceRecordId": "C-58210",
                      "linkType": "Auto"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "The `X-Api-Key` header is missing, or the key isn't valid: it may have been revoked.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.2",
                  "title": "Unauthorized",
                  "status": 401,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "404": {
            "description": "The source has no record with this ID.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
                  "title": "Record not found.",
                  "status": 404,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests with this key: at most 600 a minute. Wait the number of seconds in the `Retry-After` header (up to 60), then retry.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait, up to 60.",
                "schema": {
                  "type": "integer"
                },
                "example": 60
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "title": "Too Many Requests",
                  "status": 429,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      }
    },
    "/api/v1/snapshots": {
      "post": {
        "tags": [
          "Snapshots"
        ],
        "summary": "Open a snapshot",
        "description": "Starts a complete list of the source's records. Any earlier snapshot of the source that's still open, or held, is discarded: the newer list replaces it.",
        "operationId": "OpenSnapshot",
        "responses": {
          "201": {
            "description": "Opened.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SnapshotResponse"
                },
                "example": {
                  "snapshotId": "3f2b8c1e-9d4a-4e7b-a1c5-6d8e2f4b9a07"
                }
              }
            }
          },
          "401": {
            "description": "The `X-Api-Key` header is missing, or the key isn't valid: it may have been revoked.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.2",
                  "title": "Unauthorized",
                  "status": 401,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "409": {
            "description": "Rarely, a file being imported into the source in Samesake changed at the same moment. Retry the request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.10",
                  "title": "The record was changed by another request at the same time. Retry the request.",
                  "status": 409,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests with this key: at most 600 a minute. Wait the number of seconds in the `Retry-After` header (up to 60), then retry.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait, up to 60.",
                "schema": {
                  "type": "integer"
                },
                "example": 60
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "title": "Too Many Requests",
                  "status": 429,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      }
    },
    "/api/v1/snapshots/{snapshotId}/records": {
      "post": {
        "tags": [
          "Snapshots"
        ],
        "summary": "Add records to a snapshot",
        "description": "Sends up to 1,000 of the source's records to an open snapshot, as many times as you need. Each record is created or updated straight away, as by **Create or update records in a batch**, and counts as in the list.",
        "operationId": "PushSnapshotRecords",
        "parameters": [
          {
            "name": "snapshotId",
            "in": "path",
            "description": "The snapshot's ID, returned when it was opened.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "3f2b8c1e-9d4a-4e7b-a1c5-6d8e2f4b9a07"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "maxItems": 1000,
                "minItems": 1,
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/RecordInput"
                }
              },
              "example": [
                {
                  "sourceRecordId": "CRM-10042",
                  "firstName": "Priya",
                  "lastName": "Sharma",
                  "email": "priya.sharma@example.com",
                  "phones": [
                    "07700 900123"
                  ]
                },
                {
                  "sourceRecordId": "CRM-10043",
                  "title": "Mr",
                  "firstName": "Tom",
                  "lastName": "Fletcher",
                  "dateOfBirth": "12/09/1979",
                  "postcode": "M1 4BT",
                  "phones": [
                    "07700 900456"
                  ]
                }
              ]
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "What happened to each record, in the order they were sent.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/UpsertResult"
                  }
                },
                "example": [
                  {
                    "sourceRecordId": "CRM-10042",
                    "recordId": "rec_7k2m9xq4ht3b",
                    "outcome": "Created"
                  },
                  {
                    "sourceRecordId": "CRM-10043",
                    "recordId": "rec_3n8p2w6c9r4d",
                    "outcome": "Updated"
                  }
                ]
              }
            }
          },
          "400": {
            "description": "The request isn't valid. When a field breaks a limit, `errors` names the field and says why. A body that isn't JSON of the right shape gets this status without `errors`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
                  "title": "One or more validation errors occurred.",
                  "status": 400,
                  "errors": {
                    "[1].email": [
                      "email must be at most 200 characters."
                    ]
                  },
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "401": {
            "description": "The `X-Api-Key` header is missing, or the key isn't valid: it may have been revoked.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.2",
                  "title": "Unauthorized",
                  "status": 401,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "404": {
            "description": "The source has no snapshot with this ID.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
                  "title": "Snapshot not found.",
                  "status": 404,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "409": {
            "description": "The snapshot isn't open: it has been completed, or a newer snapshot replaced it. (Rarely, another request changed the same record at the same time: then retry.)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.10",
                  "title": "Snapshot is not open.",
                  "status": 409,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "413": {
            "description": "The request body is too large: at most 64 KB for one record, 8 MB for a batch or a snapshot's records.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.14",
                  "title": "Request body is too large.",
                  "status": 413,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "415": {
            "description": "The body isn't sent as JSON: set the `Content-Type` header to `application/json`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.16",
                  "title": "Unsupported Media Type",
                  "status": 415,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests with this key: at most 600 a minute. Wait the number of seconds in the `Retry-After` header (up to 60), then retry.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait, up to 60.",
                "schema": {
                  "type": "integer"
                },
                "example": 60
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "title": "Too Many Requests",
                  "status": 429,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      }
    },
    "/api/v1/snapshots/{snapshotId}/complete": {
      "post": {
        "tags": [
          "Snapshots"
        ],
        "summary": "Complete a snapshot",
        "description": "Says the list is complete. The source's records that weren't sent to the snapshot are deleted (`Applied`), unless that would delete more than 10% of the source's records: then nothing is deleted and the snapshot is `Held` for an admin to apply or discard in Samesake. Records created or changed after the snapshot was opened, by other calls, are never deleted by it.",
        "operationId": "CompleteSnapshot",
        "parameters": [
          {
            "name": "snapshotId",
            "in": "path",
            "description": "The snapshot's ID, returned when it was opened.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "3f2b8c1e-9d4a-4e7b-a1c5-6d8e2f4b9a07"
          }
        ],
        "responses": {
          "200": {
            "description": "Completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SnapshotCompletionResponse"
                },
                "example": {
                  "status": "Applied",
                  "missingCount": 3
                }
              }
            }
          },
          "401": {
            "description": "The `X-Api-Key` header is missing, or the key isn't valid: it may have been revoked.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.2",
                  "title": "Unauthorized",
                  "status": 401,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "404": {
            "description": "The source has no snapshot with this ID.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
                  "title": "Snapshot not found.",
                  "status": 404,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "409": {
            "description": "The snapshot isn't open: it has been completed, or a newer snapshot replaced it. (Rarely, another request changed the same record at the same time: then retry.)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.10",
                  "title": "Snapshot is not open.",
                  "status": 409,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests with this key: at most 600 a minute. Wait the number of seconds in the `Retry-After` header (up to 60), then retry.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait, up to 60.",
                "schema": {
                  "type": "integer"
                },
                "example": 60
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "title": "Too Many Requests",
                  "status": 429,
                  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "HttpValidationProblemDetails": {
        "required": [
          "title",
          "status",
          "traceId"
        ],
        "type": "object",
        "properties": {
          "type": {
            "type": [
              "null",
              "string"
            ],
            "description": "A link to the part of the HTTP standard (RFC 9110) that defines the status. Not sent with 429."
          },
          "title": {
            "type": "string",
            "description": "What went wrong, in a sentence."
          },
          "status": {
            "type": "integer",
            "description": "The HTTP status code.",
            "format": "int32"
          },
          "traceId": {
            "type": "string",
            "description": "This request's ID. Quote it if you ask us about the error."
          },
          "errors": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Each field that breaks a limit, with what's wrong with it. In a batch, the field is named by the record's position, counting from 0: `[2].email`."
          }
        },
        "description": "What went wrong, as a problem details object (RFC 9457), with `errors` when a field breaks a limit."
      },
      "LinkedRecordView": {
        "required": [
          "recordId",
          "sourceSystemCode",
          "sourceRecordId",
          "linkType"
        ],
        "type": "object",
        "properties": {
          "recordId": {
            "examples": [
              "rec_3n8p2w6c9r4d"
            ],
            "type": "string",
            "description": "Samesake's ID for the record."
          },
          "sourceSystemCode": {
            "examples": [
              "SHOP"
            ],
            "type": "string",
            "description": "The code of the record's source."
          },
          "sourceRecordId": {
            "examples": [
              "C-58210"
            ],
            "type": "string",
            "description": "The source's own ID for the record."
          },
          "linkType": {
            "$ref": "#/components/schemas/LinkType"
          }
        },
        "description": "A record matched to another."
      },
      "LinkType": {
        "enum": [
          "Auto",
          "Confirmed"
        ],
        "type": "string",
        "description": "`Auto`: Samesake matched the records itself. `Confirmed`: a reviewer confirmed the match."
      },
      "ProblemDetails": {
        "required": [
          "title",
          "status",
          "traceId"
        ],
        "type": "object",
        "properties": {
          "type": {
            "type": [
              "null",
              "string"
            ],
            "description": "A link to the part of the HTTP standard (RFC 9110) that defines the status. Not sent with 429."
          },
          "title": {
            "type": "string",
            "description": "What went wrong, in a sentence."
          },
          "status": {
            "type": "integer",
            "description": "The HTTP status code.",
            "format": "int32"
          },
          "traceId": {
            "type": "string",
            "description": "This request's ID. Quote it if you ask us about the error."
          }
        },
        "description": "What went wrong, as a problem details object (RFC 9457)."
      },
      "RecordIdResponse": {
        "required": [
          "recordId"
        ],
        "type": "object",
        "properties": {
          "recordId": {
            "type": "string",
            "description": "Samesake's ID for the record. It never changes, so you can store it beside your own."
          }
        },
        "description": "The record written."
      },
      "RecordInput": {
        "required": [
          "sourceRecordId"
        ],
        "type": "object",
        "properties": {
          "sourceRecordId": {
            "examples": [
              "CRM-10042"
            ],
            "maxLength": 100,
            "minLength": 1,
            "type": "string",
            "description": "Your ID for the record in this source, such as a contact ID. Required, and not blank. Sending a record with the same ID again updates it. Spaces at either end are ignored."
          },
          "title": {
            "examples": [
              "Ms"
            ],
            "maxLength": 200,
            "type": [
              "null",
              "string"
            ],
            "description": "Title, such as Mr, Mrs, Ms or Dr."
          },
          "firstName": {
            "examples": [
              "Priya"
            ],
            "maxLength": 200,
            "type": [
              "null",
              "string"
            ],
            "description": "First name."
          },
          "lastName": {
            "examples": [
              "Sharma"
            ],
            "maxLength": 200,
            "type": [
              "null",
              "string"
            ],
            "description": "Last name."
          },
          "email": {
            "examples": [
              "priya.sharma@example.com"
            ],
            "maxLength": 200,
            "type": [
              "null",
              "string"
            ],
            "description": "Email address."
          },
          "dateOfBirth": {
            "examples": [
              "1986-04-03"
            ],
            "maxLength": 200,
            "type": [
              "null",
              "string"
            ],
            "description": "Date of birth, best as yyyy-mm-dd. Day-first forms such as dd/mm/yyyy, dd-mm-yyyy and dd.mm.yyyy are read too: 03/04/1986 is 3 April."
          },
          "addressLine1": {
            "examples": [
              "14 Larch Grove"
            ],
            "maxLength": 200,
            "type": [
              "null",
              "string"
            ],
            "description": "First line of the address, such as the house number and street."
          },
          "addressLine2": {
            "examples": [
              "Manchester"
            ],
            "maxLength": 200,
            "type": [
              "null",
              "string"
            ],
            "description": "Second line of the address, such as the town."
          },
          "postcode": {
            "examples": [
              "M20 6RT"
            ],
            "maxLength": 200,
            "type": [
              "null",
              "string"
            ],
            "description": "UK postcode, with or without the space."
          },
          "phones": {
            "examples": [
              [
                "07700 900123",
                "0161 496 0123"
              ]
            ],
            "maxItems": 10,
            "type": [
              "null",
              "array"
            ],
            "items": {
              "maxLength": 200,
              "type": "string"
            },
            "description": "Phone numbers, mobile or landline, in any usual format: 07700 900123, +44 7700 900123, (0161) 496 0123, +49 30 1234567. A number without a country code is read as belonging to the country chosen when your Samesake account was set up (usually the United Kingdom), so the same digits under two different country codes are two different numbers."
          }
        },
        "description": "A record as your system holds it. Every field except `sourceRecordId` is optional, and each request sends the whole record: a field left out or sent as null is cleared. Values aren't rejected for being badly formed: a date, phone number or postcode Samesake can't read is kept as sent, but not used for matching."
      },
      "RecordReplacement": {
        "type": "object",
        "properties": {
          "title": {
            "examples": [
              "Ms"
            ],
            "maxLength": 200,
            "type": [
              "null",
              "string"
            ],
            "description": "Title, such as Mr, Mrs, Ms or Dr."
          },
          "firstName": {
            "examples": [
              "Priya"
            ],
            "maxLength": 200,
            "type": [
              "null",
              "string"
            ],
            "description": "First name."
          },
          "lastName": {
            "examples": [
              "Sharma"
            ],
            "maxLength": 200,
            "type": [
              "null",
              "string"
            ],
            "description": "Last name."
          },
          "email": {
            "examples": [
              "priya.sharma@example.com"
            ],
            "maxLength": 200,
            "type": [
              "null",
              "string"
            ],
            "description": "Email address."
          },
          "dateOfBirth": {
            "examples": [
              "1986-04-03"
            ],
            "maxLength": 200,
            "type": [
              "null",
              "string"
            ],
            "description": "Date of birth, best as yyyy-mm-dd. Day-first forms such as dd/mm/yyyy, dd-mm-yyyy and dd.mm.yyyy are read too: 03/04/1986 is 3 April."
          },
          "addressLine1": {
            "examples": [
              "14 Larch Grove"
            ],
            "maxLength": 200,
            "type": [
              "null",
              "string"
            ],
            "description": "First line of the address, such as the house number and street."
          },
          "addressLine2": {
            "examples": [
              "Manchester"
            ],
            "maxLength": 200,
            "type": [
              "null",
              "string"
            ],
            "description": "Second line of the address, such as the town."
          },
          "postcode": {
            "examples": [
              "M20 6RT"
            ],
            "maxLength": 200,
            "type": [
              "null",
              "string"
            ],
            "description": "UK postcode, with or without the space."
          },
          "phones": {
            "examples": [
              [
                "07700 900123",
                "0161 496 0123"
              ]
            ],
            "maxItems": 10,
            "type": [
              "null",
              "array"
            ],
            "items": {
              "maxLength": 200,
              "type": "string"
            },
            "description": "Phone numbers, mobile or landline, in any usual format: 07700 900123, +44 7700 900123, (0161) 496 0123, +49 30 1234567. A number without a country code is read as belonging to the country chosen when your Samesake account was set up (usually the United Kingdom), so the same digits under two different country codes are two different numbers."
          }
        },
        "description": "A record's fields, replacing all of its current ones: a field left out or sent as null is cleared. There's no `sourceRecordId`, because the path names the record (one sent anyway is ignored). Values aren't rejected for being badly formed: a date, phone number or postcode Samesake can't read is kept as sent, but not used for matching."
      },
      "RecordView": {
        "required": [
          "recordId",
          "sourceSystemCode",
          "sourceRecordId",
          "title",
          "firstName",
          "lastName",
          "email",
          "dateOfBirth",
          "addressLine1",
          "addressLine2",
          "postcode",
          "phones",
          "personId",
          "deleted",
          "linkedRecords"
        ],
        "type": "object",
        "properties": {
          "recordId": {
            "examples": [
              "rec_7k2m9xq4ht3b"
            ],
            "type": "string",
            "description": "Samesake's ID for the record. It never changes."
          },
          "sourceSystemCode": {
            "examples": [
              "CRM"
            ],
            "type": "string",
            "description": "The code of the record's source."
          },
          "sourceRecordId": {
            "examples": [
              "CRM-10042"
            ],
            "type": "string",
            "description": "Your ID for the record in its source."
          },
          "title": {
            "examples": [
              "Ms"
            ],
            "type": [
              "null",
              "string"
            ],
            "description": "Title."
          },
          "firstName": {
            "examples": [
              "Priya"
            ],
            "type": [
              "null",
              "string"
            ],
            "description": "First name."
          },
          "lastName": {
            "examples": [
              "Sharma"
            ],
            "type": [
              "null",
              "string"
            ],
            "description": "Last name."
          },
          "email": {
            "examples": [
              "priya.sharma@example.com"
            ],
            "type": [
              "null",
              "string"
            ],
            "description": "Email address."
          },
          "dateOfBirth": {
            "examples": [
              "1986-04-03"
            ],
            "type": [
              "null",
              "string"
            ],
            "description": "Date of birth, as sent."
          },
          "addressLine1": {
            "examples": [
              "14 Larch Grove"
            ],
            "type": [
              "null",
              "string"
            ],
            "description": "First line of the address."
          },
          "addressLine2": {
            "examples": [
              "Manchester"
            ],
            "type": [
              "null",
              "string"
            ],
            "description": "Second line of the address."
          },
          "postcode": {
            "examples": [
              "M20 6RT"
            ],
            "type": [
              "null",
              "string"
            ],
            "description": "Postcode, as sent."
          },
          "phones": {
            "examples": [
              [
                "07700 900123",
                "0161 496 0123"
              ]
            ],
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Phone numbers, as sent."
          },
          "personId": {
            "examples": [
              "per_5d9h2k7m3x8q"
            ],
            "type": [
              "null",
              "string"
            ],
            "description": "Samesake's ID for the person the record belongs to: every record matched to the same person has the same one. Null until the record has been matched. It changes if people are merged or split."
          },
          "deleted": {
            "type": "boolean",
            "description": "Whether the record has been deleted. A deleted record's details are removed; its IDs stay."
          },
          "linkedRecords": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LinkedRecordView"
            },
            "description": "The records matched to this one, from any source: their IDs, not their details."
          }
        },
        "description": "A record as Samesake holds it: its details as the source sent them (all cleared once it's deleted), the person it belongs to, and the records matched to it."
      },
      "SnapshotCompletionResponse": {
        "required": [
          "status",
          "missingCount"
        ],
        "type": "object",
        "properties": {
          "status": {
            "description": "`Applied` if the missing records were deleted; `Held` if there were too many to delete without an admin's say-so.",
            "$ref": "#/components/schemas/SnapshotStatus"
          },
          "missingCount": {
            "type": "integer",
            "description": "How many of the source's records weren't in the snapshot.",
            "format": "int32"
          }
        },
        "description": "What completing the snapshot did."
      },
      "SnapshotResponse": {
        "required": [
          "snapshotId"
        ],
        "type": "object",
        "properties": {
          "snapshotId": {
            "type": "string",
            "description": "The snapshot's ID, for adding records to it and completing it.",
            "format": "uuid"
          }
        },
        "description": "The snapshot opened."
      },
      "SnapshotStatus": {
        "enum": [
          "Applied",
          "Held"
        ],
        "type": "string",
        "description": "What completing a snapshot did. `Applied`: the records missing from it were deleted. `Held`: it would delete more than 10% of the source's records, so nothing is deleted unless an admin applies it in Samesake."
      },
      "UpsertOutcome": {
        "enum": [
          "Created",
          "Updated",
          "Unchanged"
        ],
        "type": "string",
        "description": "`Created`: the source had no record with this ID. `Updated`: the record's details changed, or a deleted record was restored. `Unchanged`: the record already had these details."
      },
      "UpsertResult": {
        "required": [
          "sourceRecordId",
          "recordId",
          "outcome"
        ],
        "type": "object",
        "properties": {
          "sourceRecordId": {
            "examples": [
              "CRM-10042"
            ],
            "type": "string",
            "description": "Your ID for the record, as sent (without spaces at either end)."
          },
          "recordId": {
            "examples": [
              "rec_7k2m9xq4ht3b"
            ],
            "type": "string",
            "description": "Samesake's ID for the record. It never changes."
          },
          "outcome": {
            "$ref": "#/components/schemas/UpsertOutcome"
          }
        },
        "description": "What happened to one record."
      }
    },
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "description": "The source's API key. An admin issues it in Samesake, under Admin, then Sources. Keep it secret: anyone who has it can change the source's records.",
        "name": "X-Api-Key",
        "in": "header"
      }
    }
  },
  "tags": [
    {
      "name": "Records",
      "description": "A record is what one source holds about one person. Address it by Samesake's ID for it (`recordId`, returned when it's created) or by your own (`sourceRecordId`)."
    },
    {
      "name": "Snapshots",
      "description": "A snapshot is a complete list of a source's records, for systems that can't report deletions. Open one, add every record to it in batches, then complete it: the source's records that weren't added are deleted. If that would delete more than 10% of the source's records, nothing is deleted and the snapshot is held for an admin to check. Records created or changed after the snapshot was opened, by other calls, are never deleted by it."
    }
  ]
}