{
  "openapi": "3.0.3",
  "info": {
    "title": "Retail Lead Management API",
    "version": "1.0",
    "description": "The RLM v1 API lets an external system read lead data out of a Retail Lead\nManagement pipeline, and create new leads in it.\n\nThis is the long-standing public API. It is stable and will not be removed,\nbut it is limited: you can list leads, fetch one lead, and read your\norganization and pipeline configuration. There is no filtering beyond lead\nstatus and a created/updated date, and a list request returns at most 500\nleads per page.\n\nIf you need richer querying - per-field filters, sorting, pagination, or\naccess to tasks, companies, contacts, journals, attachments and samples -\nuse the [v3 read-only API](/docs/v3/) instead. v3 requires access to be\nenabled on your account; contact RLM support to request it.\n\n## Machine-readable spec\n\nThis page is generated from an OpenAPI 3.0.3 document, served alongside it:\n\n| Format | URL |\n| --- | --- |\n| JSON | [`/docs/rlm-v1.json`](/docs/rlm-v1.json) |\n| YAML | [`/docs/rlm-v1.yaml`](/docs/rlm-v1.yaml) |\n\nPoint a client generator, a request validator, or a coding assistant at\neither one rather than at this page - the two files are the same document\nthis page was built from, and the JSON is a straight parse of the YAML.\n\nTwo conventions in them are worth knowing, because they are the difference\nbetween \"these are the only values\" and \"these are the values we know\":\n\n- **`enum`** means the API constrains the value. On a response field, it is\n  the complete set of values the API will ever send.\n- **`x-recognised-values`** means the value set is known and fixed but *not*\n  enforced - RLM understands these values and stores anything else as sent.\n  `LeadCreate.state` is the one that matters. A validator must not treat it\n  as an `enum`, because a request outside the list is still accepted.\n\nValues that are configured per pipeline - lead sources, product lines,\nstage names - cannot appear as either. Read those from\n`GET /api/v1/pipeline/{apiKey}` at runtime; each field that works this way\nsays so and names where in that response to look.\n\n## Base path\n\n**Every endpoint on this page is prefixed `/api/v1/`, with one exception.**\nRead the path printed on each operation as the complete path: nothing is\nadded to it for you.\n\n| Exception | Path | Why |\n| --- | --- | --- |\n| Create a lead | `POST /api/{apiKey}/leads` | Predates the versioned API. Left where it is because moving it would break every integration posting to it. |\n\nSo a read is `https://app.retailleadmanagement.com/api/v1/organization`,\nwhile creating a lead is\n`https://app.retailleadmanagement.com/api/0123.../leads` - no `v1`.\n\nThat one endpoint differs in more than its path: it takes no authentication\nheaders, and its `{apiKey}` is the pipeline key rather than an\norganization key. Both differences are covered below and on the operation\nitself.\n\n## Authentication\n\nRequests to the four read endpoints under `/api/v1/` must send two\nheaders:\n\n| Header | Value |\n| --- | --- |\n| `X-Api-Key` | Your **organization** API key |\n| `X-User-Email` | The email address of an RLM user in that organization |\n\n`POST /api/{apiKey}/leads` - the unprefixed endpoint from the table above -\nis the exception. It takes **no headers at all**: the pipeline API key in\nits URL is the only credential it reads, and a request that omits both\nheaders is accepted and returns `201`. Do not hand an organization API key\nto a form vendor or any other third party writing leads for you - see that\nendpoint for the reasoning.\n\nThese are two different keys and mixing them up is the single most common\nintegration mistake:\n\n- The **organization API key** goes in the `X-Api-Key` header. It\n  authenticates the request. Ask RLM support for it.\n- The **pipeline API key** goes in the URL path, as the `{apiKey}` segment.\n  It selects which pipeline you are reading from. An organization can have\n  several pipelines, each with its own key.\n\n`X-User-Email` determines *what you can see*. Every lead endpoint is scoped\nto the pipeline named by `{apiKey}` **and** narrowed to what that user may\nview in the RLM web app, so the same request run as two different users can\nreturn different sets.\n\nRLM has six roles. For the lead endpoints they fall into three groups:\n\n| Role | What the lead endpoints return |\n| --- | --- |\n| System Admin, Business Admin, Business Manager, Full View | The pipeline's leads, narrowed to the pipelines, divisions and locations that user may see |\n| Single View | Only the leads in that pipeline **assigned to them** |\n| Assistant | Only the leads they created that are still pending and unassigned |\n\n**Full View is not a manager role.** It shares the top row above because it\nsees the whole pipeline, but that is breadth of visibility, not seniority.\nRLM's manager roles are System Admin, Business Admin and Business Manager;\nFull View and Single View are salesperson roles, and their older names in\nthe database still say so - `Sales Person Full View` and `Sales Person\nSingle View`.\n\nThe distinction has teeth: `deleted` on **List leads** is the one thing that\nneeds an actual manager, and a Full View user gets an empty list from it\ndespite seeing every live lead in the pipeline.\n\nTwo more consequences worth planning around:\n\n- A Single View or Assistant user's leads in *other* pipelines are never\n  included, whichever key you ask with - ask with that pipeline's own key to\n  retrieve those.\n- An Assistant ignores the `{status}` segment entirely. Pending and\n  unassigned is the whole of what they may see, so `closed`, `all` and\n  `deleted` all return what `open` returns.\n\nPick the user whose visibility matches the data set you intend to sync. If a\nsync returns fewer leads than you expect, check the user's role first, then\ntheir pipeline, division and location permissions, before suspecting the\nrequest.\n\n**The two headers must agree.** The user named in `X-User-Email` must belong\nto the organization that `X-Api-Key` authenticates as. Pairing your own\norganization key with someone else's email returns `422`, exactly like an\nunrecognised key - v1 does not distinguish \"wrong credentials\" from \"not\nallowed\".\n\nPipeline visibility is a separate matter and is *not* an authentication\ncheck: a user who cannot see the pipeline still authenticates successfully\nand simply gets an empty result set. If a request suddenly returns no leads\nrather than an error, check what that user can see in the web app before\nsuspecting your credentials.\n\n## Response codes\n\nSuccessful reads on this API return **`201 Created`**, not `200 OK`. This is\ntrue for the GET endpoints as well. It is a long-standing quirk of the v1\nimplementation and changing it now would break existing integrations, so it\nis documented rather than fixed. **Treat any 2xx as success** rather than\nchecking for `200`.\n\nAlmost every failure - unknown organization key, unknown user email, wrong\npipeline key, a user who may not see the pipeline - returns **`422\nUnprocessable Entity`** with a `{\"result\": \"Bad Request\"}` body. v1 does not\ndistinguish authentication failures from authorization failures, and never\nreturns `401` or `403`.\n\nThere is one exception: `GET /api/v1/pipeline/{apiKey}/lead/{leadId}`\nanswers **`404`** when the lead id does not exist in that pipeline, and a\nclient that handles only `2xx` and `422` will fall through on it. Treat it\nas \"no lead was returned\".\n\nThat `404` body is an **HTML page**, not JSON - `Content-Type: text/html`,\nroughly 15 KB of markup. Calling `JSON.parse` on it raises. **Do not assume\na non-2xx response parses as JSON**: branch on the status code first, and\nparse the body only when the response declares `application/json`. The same\nis true of any unexpected `500`.\n\n## Rate limits\n\nEvery endpoint on this page - the `/api/v1/*` reads and\n`POST /api/{apiKey}/leads` alike - is limited to **20 requests per\nsecond**, measured per source IP over a 5 second window. The `/api/v1/*`\nreads are measured per set of credentials as well, at the same rate, so\nspreading a job across several machines does not raise its allowance. It is\none shared budget, not 20 per endpoint: a busy lead feed and a polling sync\nrunning from the same IP spend the same allowance. Exceeding it returns\n`429 Too Many Requests` with a `Retry-After` header.\n",
    "contact": {
      "name": "RLM Support"
    }
  },
  "servers": [
    {
      "url": "https://app.retailleadmanagement.com",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Leads",
      "description": "Read and create leads."
    },
    {
      "name": "Configuration",
      "description": "Read how your organization and pipelines are set up - which pipelines,\nlocations and divisions exist, and which field names appear on lead\nobjects. Pipeline API keys are not discoverable here; ask RLM support.\n"
    }
  ],
  "security": [
    {
      "OrganizationApiKey": [

      ],
      "UserEmail": [

      ]
    }
  ],
  "paths": {
    "/api/v1/organization": {
      "get": {
        "tags": [
          "Configuration"
        ],
        "operationId": "fetchOrganization",
        "summary": "Get organization info",
        "description": "Returns the organization identified by the `X-Api-Key` header, including\nits locations, divisions and pipelines.\n\nCall this first: the `pipelines[].id` and `pipelines[].name` values tell\nyou which pipelines exist and which one you mean.\n\n**This response does not contain pipeline API keys.** Ask RLM support\nfor the key of the pipeline you want to read; it is the `{apiKey}` path\nsegment on every other endpoint.\n",
        "responses": {
          "201": {
            "description": "The organization. Note the non-standard success code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Organization"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/api/v1/pipeline/{apiKey}": {
      "get": {
        "tags": [
          "Configuration"
        ],
        "operationId": "fetchPipelineData",
        "summary": "Get pipeline configuration",
        "description": "Returns the configuration of a single pipeline: its fields, its lead\nstatuses, and the locations and divisions available to it.\n\nThis is how you discover field names. A lead object carries the custom\nfields configured for its pipeline, so the `pipeline_fields[]` entries\nhere tell you which keys to expect on a lead and what type each holds.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/PipelineApiKey"
          }
        ],
        "responses": {
          "201": {
            "description": "The pipeline configuration.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Pipeline"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/api/v1/pipeline/{apiKey}/leads/{status}": {
      "get": {
        "tags": [
          "Leads"
        ],
        "operationId": "fetchLeads",
        "summary": "List leads",
        "description": "Returns every lead in the pipeline matching `{status}` that the user in\n`X-User-Email` is allowed to see, most recently updated first.\n\n**A response carries at most 500 leads.** This is a page, not a\ntruncation: send no paging parameters and you get the first 500, exactly\nas if you had asked for page 1. A different limit may be configured for\nyour account.\n\n⚠️ **If you previously received more than 500 leads from one call, you\nnow receive 500 and must follow the pages to get the rest.** Nothing\nerrors, so an integration that ignores the `Link` header below will\nquietly process only the first page. This is the one thing to check\nbefore this change reaches you.\n\n**Read the rest with `page[number]` and `page[size]`.** Asking for a\n`page[size]` above the limit - or below 1 - is refused with `422` and the\nstandard error envelope rather than quietly given a different number, so\nyou always know what you asked for. Nothing else about the size of the\nresult set can produce an error.\n\n**Paging is advertised in a `Link` header** (RFC 8288) on every response,\nincluding the `422` and including requests that asked for no page, with\n`rel=\"first\"`, `rel=\"prev\"` and `rel=\"next\"` as applicable. The\n**response body is identical whether or not you paged** - always a single\n`data` array, never a wrapper - so adding paging to an existing\nintegration cannot change what it parses. Walk until no `rel=\"next\"` is\npresent.\n\nThere is no `rel=\"last\"` and no total count: producing either would cost\na full scan of the matching set on every request.\n\n⚠️ Pages are cut from a list ordered by **most recently updated first**,\nand that ordering moves as leads are updated - so a lead can shift\nbetween pages while you walk them. For an unattended sync, page within a\nfixed `by_datetime_since` window rather than paging the whole history,\nor use the v3 API, whose ordering can be pinned to the immutable `id`.\n\nFor routine syncing, prefer `open` and narrow with the date parameters\nbelow rather than pulling `all` repeatedly.\n\n**Leads with no location or no division are dropped.** Restricting this\nlist to the pipelines, divisions and locations the user may see is an\ninner join on all three, so a lead whose `location` or `division` is\nempty matches nothing and never appears here - even though `Lead`\ndocuments both as nullable, and even though\n`GET /api/v1/pipeline/{apiKey}/lead/{leadId}` returns that same lead\nwithout complaint. If a lead is visible in the web app but never\nreaches your integration, check those two fields first.\n\n### Incremental syncing\n\nTo poll for changes, send `by_date=updated` together with\n`by_datetime_since` set to the timestamp of your last successful sync:\n\n```\n?by_date=updated&by_datetime_since=2026-08-05%2014:30:00\n```\n\n**The two date parameters do not use the same clock.**\n`by_datetime_since` is interpreted in your organization's configured\ntime zone; `by_date_at` is a **UTC** calendar day and ignores your time\nzone entirely. For a Pacific dealer that means every lead taken after\n5 p.m. local counts as the following UTC day.\n\nTwo more traps worth wiring around before you go live:\n\n- Send a full timestamp, not a bare date. `by_datetime_since=2026-08-05`\n  is read as **noon** on that day, so it silently skips the morning.\n- A `by_datetime_since` value that cannot be parsed - or a missing one -\n  is not an error. It becomes a comparison against nothing, and the\n  response is `201` with an empty `data` array. A wrong timestamp\n  format therefore looks identical to \"no new leads\", forever. If a\n  sync goes permanently quiet, re-check the value you are sending.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/PipelineApiKey"
          },
          {
            "name": "status",
            "in": "path",
            "required": true,
            "description": "Which leads to return.\n\n- `open` - leads still moving through the pipeline\n- `closed` - leads in a closed status (sold, no-sale, dead, ...)\n- `all` - open and closed\n- `deleted` - soft-deleted leads. Requires the `X-User-Email` user\n  to hold one of RLM's three **manager** roles: System Admin,\n  Business Admin or Business Manager. Anyone below that gets `201`\n  with an empty `data` array rather than an error, so check the role\n  if this comes back empty unexpectedly.\n\n  **A Full View user is below that line**, even though every other\n  value of `{status}` returns them the whole pipeline. Full View is\n  a salesperson role, not a manager one - see Authentication. This\n  is the only place on the v1 API where the two come apart, and it\n  is the usual reason a `deleted` sync returns nothing.\n\nAny unrecognised value is treated as `open`.\n",
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "closed",
                "all",
                "deleted"
              ]
            },
            "example": "open"
          },
          {
            "name": "by_date",
            "in": "query",
            "required": false,
            "description": "Restrict to leads by date. Choose which date to filter on, then\nsupply exactly one of `by_date_at` or `by_datetime_since`.\n\nOmit `by_date` entirely and no date filtering is applied - the other\ntwo parameters are ignored on their own.\n\nSending `by_date` *without* either of them is not an error and does\nnot mean \"no filter\": the response is an empty list.\n",
            "schema": {
              "type": "string",
              "enum": [
                "created",
                "updated"
              ]
            },
            "example": "updated"
          },
          {
            "name": "by_date_at",
            "in": "query",
            "required": false,
            "description": "A single calendar day, as `YYYY-MM-DD`. Returns leads created or\nupdated on that day. Takes precedence over `by_datetime_since`.\n\n**The day is a UTC day**, not a day in your organization's time\nzone: the comparison is made against the stored UTC timestamp. A\nPacific dealer asking for `2026-08-05` gets leads from 5 p.m. on\n2026-08-04 through 4:59 p.m. on 2026-08-05 local time, and a lead\ntaken at 11 p.m. on the 5th answers to `by_date_at=2026-08-06`.\nWhere the boundary matters, use `by_datetime_since`, which does\nrespect your zone.\n",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-08-05"
          },
          {
            "name": "by_datetime_since",
            "in": "query",
            "required": false,
            "description": "Return leads created or updated at or after this point in time,\nread in your organization's configured time zone. Used only when\n`by_date_at` is absent.\n\nParsed leniently, so `2026-08-05 14:30:00`, `2026-08-05` and\nrelative phrasings such as `yesterday` or `2 hours ago` all work.\nAlways send an explicit `YYYY-MM-DD HH:MM:SS` timestamp from an\nautomated integration, for two concrete reasons:\n\n- A value with no time of day means **noon**, not midnight.\n  `2026-08-05` starts the window at `2026-08-05 12:00:00`, and\n  `yesterday` behaves the same way, so half the day you asked for\n  is missing from the answer.\n- A value the parser cannot make sense of is discarded rather than\n  rejected. The filter then compares against nothing and matches no\n  rows, so a malformed timestamp returns `201` with an empty `data`\n  array instead of an error. Same for omitting this parameter while\n  still sending `by_date`.\n",
            "schema": {
              "type": "string"
            },
            "example": "2026-08-05 14:30:00"
          },
          {
            "name": "page[number]",
            "in": "query",
            "required": false,
            "description": "Which page to return, counting from 1. Defaults to 1, so omitting it\ngives you the first page.\n\nA value below 1, or one that is not a number, is treated as absent\nand you get page 1. A page past the end returns `201` with an empty\n`data` array and no `rel=\"next\"` - that is the normal way a walk\nends, alongside a short final page.\n",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 1
          },
          {
            "name": "page[size]",
            "in": "query",
            "required": false,
            "description": "How many leads a page may carry. Defaults to the limit that applies\nto your account - 500 unless yours is set otherwise.\n\nA value above that limit, or below 1, is **refused with `422`**\nrather than quietly replaced with a different number, so a page you\nreceive is always the size you asked for. A value that is not a\nnumber at all is treated as absent and you get the default.\n",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500
            },
            "example": 200
          }
        ],
        "responses": {
          "201": {
            "description": "Matching leads. Note the non-standard success code.",
            "headers": {
              "Link": {
                "$ref": "#/components/headers/Pagination"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Lead"
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/api/v1/pipeline/{apiKey}/lead/{leadId}": {
      "get": {
        "tags": [
          "Leads"
        ],
        "operationId": "fetchLead",
        "summary": "Get a single lead",
        "description": "Returns one lead by its RLM id, in the same shape as an entry in the\nlist response.\n\nThis endpoint does not use the `422` JSON envelope for every failure. It\nalso returns **`404`** when the lead id does not exist in this pipeline,\nwith an HTML body rather than JSON. Branch on the status before parsing.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/PipelineApiKey"
          },
          {
            "name": "leadId",
            "in": "path",
            "required": true,
            "description": "The RLM lead id, as returned in the `id` field of a lead.",
            "schema": {
              "type": "integer"
            },
            "example": 1234567
          }
        ],
        "responses": {
          "201": {
            "description": "The lead. Note the non-standard success code.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Lead"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/LeadNotFound"
          },
          "422": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/api/{apiKey}/leads": {
      "post": {
        "tags": [
          "Leads"
        ],
        "operationId": "createLead",
        "summary": "Create a lead",
        "description": "Creates a lead in the pipeline identified by `{apiKey}`.\n\nNote that this endpoint is **not** under `/api/v1/` - its path is\n`/api/{apiKey}/leads`.\n\n### It takes no headers\n\nThe pipeline API key in the URL is the entire credential. This\noperation never reads `X-Api-Key` or `X-User-Email`; a request that\nsends neither is accepted and returns `201`.\n\nThat has one important consequence. When a web-form vendor, chat\nwidget or marketing platform posts leads on your behalf, give them the\n**pipeline** key and nothing else. **Do not give a third party your\norganization API key for this endpoint** - it is not used here, and it\nis the credential that reads every lead in your organization through\n`/api/v1/`. A pipeline key only writes into the one pipeline it names.\n\n### Four reserved keys change the shape of the request\n\nBefore anything else, RLM looks at the top level of the body for `lead`,\n`contact`, `rawRequest` or `api`, in that order. **If one is present,\nits contents replace the entire payload** and every other top-level key\nis discarded. This is how form vendors post: a JotForm webhook sends\n`rawRequest`, and `lead` and `contact` wrap a lead the same way.\n\n| Key | What it must hold | Anything else |\n| --- | --- | --- |\n| `lead`, `contact`, `api` | An object of the lead's fields | A string, number or array answers **`500`** |\n| `rawRequest` | A **string** of JSON | An object, or a string that is not JSON, answers **`500`** |\n\n**Treat all four names as reserved.** `{\"api\": \"web\"}` is not a lead\nwith an `api` field - it is a malformed envelope, and it answers `500`\nrather than the `201` an unrecognised key would get. If you need to send\na field called `lead`, `contact`, `api` or `rawRequest`, ask RLM support\nto configure an `api_field_name` for it and send that name instead.\n\nIf none of the four is present, the body itself is the payload. That is\nthe ordinary case, and everything below describes it.\n\n### How keys are matched\n\nPost a single lead object. For each key, RLM looks first for a pipeline\nfield whose `api_field_name` matches, and failing that for a column on\nthe lead with that name - which in practice is the field's\n`column_name`. Keys are lower-cased before either lookup.\n\n`api_field_name` is an optional alias that somebody has to configure\ndeliberately, and most pipelines have none set on any field, so\n`column_name` - as listed in `pipeline_fields[]` by\n`GET /api/v1/pipeline/{apiKey}` - is the normal answer to \"what do I\ncall this field?\". Use `api_field_name` when the pipeline configuration\nshows one.\n\nNeither is the label you see on a lead in RLM. A field shown as\n**Lead Source** is `source_name` on the wire, and the two are edited\nindependently - see `PipelineField` for how each key maps to the\npipeline's field settings. Give RLM support the display name when\nasking which key a field uses; give your own code the `column_name`.\n\nA key matching neither is appended to the new lead as a note rather\nthan being rejected, so a misspelled key name fails quietly. The note\nline uses the humanized key, so a stray `first_name` reads\n`First name: Jane` - not `first_name: Jane`. A `note` key is written\ninto the note verbatim, with no prefix.\n\nSome keys reach neither a field nor the note: `formid`, `uniqueid`,\n`handshakekey`, `controller`, `action`, `api_key`,\n`salesperson_assignment`, `id`, `location_id`, `division_id`,\n`location_name`, `division_name`, and **any key whose value is blank**.\nSeveral of those are acted on elsewhere in the request - the location\nand division keys file the lead - but none of them survive as a note,\nso do not rely on the note as a full record of what you posted.\n\nThe four reserved keys above are not in that list because they never get\nthis far: they are read before the payload is walked, and a malformed\none fails the request outright.\n\n### What you get back\n\nThe new lead is placed in the pipeline's initial status, and filed\nunder the pipeline's default location and division unless the request\nsupplies its own.\n\nIt is **attributed to** the pipeline's default salesperson, who is\nrecorded as its creator - but it is not *assigned* to anyone. A lead\ncreated here comes back with `salesperson` and `salesperson_id` null\nand `unassigned` true, and stays that way until someone takes it in the\nweb app. Do not read `salesperson` on a fresh lead to decide who owns\nit.\n\n**An empty or unrecognised payload does not fail.** No key is required.\nPost an empty body and you get `201` and a blank lead sitting in the\npipeline; post a body whose keys match nothing and you get `201` and a\nlead that is only a note. Validate the payload before you send it -\nnothing on this side will do it for you, and there is no response you\ncan check for \"that was not a real lead\".\n\nThe one exception is a malformed envelope: a top-level `lead`,\n`contact`, `api` or `rawRequest` of the wrong type answers `500`. That\nis the only shape of body this endpoint rejects.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/PipelineApiKey"
          }
        ],
        "security": [

        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LeadCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The lead was created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "result": {
                      "type": "string",
                      "enum": [
                        "Success"
                      ]
                    },
                    "lead_id": {
                      "type": "integer",
                      "description": "The id of the newly created lead.",
                      "example": 1234567
                    },
                    "lead_uuid": {
                      "type": "string",
                      "description": "The new lead's UUID. Worth storing alongside `lead_id`:\nit is the identifier RLM's note-ingest integrations use\nto attach later messages to this lead.\n",
                      "example": "4f0a1b2c-3d4e-5f60-7182-93a4b5c6d7e8"
                    },
                    "messages": {
                      "description": "The lead's error object. Empty on a `201` - the same\nenvelope carries the validation errors on a `422`.\n"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "The pipeline key was not recognised, the lead could not be saved,\nor the pipeline is not set up to accept API leads.\n",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "result": {
                      "type": "string",
                      "enum": [
                        "Error",
                        "Invalid Request"
                      ],
                      "description": "`Invalid Request` means the `{apiKey}` in the URL matched\nno pipeline - check the key, and note that nothing else\nabout the request has been looked at. `Error` means the\npipeline was found but the lead was not saved: either it\nfailed validation, or the pipeline has no default\nsalesperson and no service account to attribute the lead\nto, which is a configuration problem for RLM support\nrather than something to retry.\n"
                    },
                    "messages": {
                      "description": "Per-field validation errors, or a single explanatory\nsentence. Absent when `result` is `Invalid Request`.\n"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "OrganizationApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Api-Key",
        "description": "Your organization's API key. This authenticates the request. It is not\nthe same as the pipeline API key that appears in the URL.\n\n32 hexadecimal characters. Example shape (a placeholder, not a usable\nkey): `0123456789abcdef0123456789abcdef`\n"
      },
      "UserEmail": {
        "type": "apiKey",
        "in": "header",
        "name": "X-User-Email",
        "description": "The email address of an RLM user in the same organization. Determines\nwhich records the response is allowed to include.\n\nExample shape: `integration-user@example.com`\n"
      }
    },
    "parameters": {
      "PipelineApiKey": {
        "name": "apiKey",
        "in": "path",
        "required": true,
        "description": "The **pipeline** API key, identifying which pipeline to read from or\nwrite to. Ask RLM support for it: no endpoint hands out the key of a\npipeline you do not already have, and neither\n`GET /api/v1/organization` nor `GET /api/v1/pipeline/{apiKey}` includes\nit in the configuration it returns.\n\nIt is not a secret kept from the read endpoints, though. A lead created\nthrough `POST /api/{apiKey}/leads` records the key it was created with,\nand every read of that lead returns it verbatim in `pipeline_api_key`.\nAnyone who can list leads can therefore collect the pipeline keys those\nleads came in through, so treat a pipeline key as visible to every user\nin the organization with API access rather than as a shared secret\nbetween you and one vendor.\n",
        "schema": {
          "type": "string"
        },
        "example": "0123456789abcdef0123456789abcdef"
      }
    },
    "headers": {
      "Pagination": {
        "description": "RFC 8288 link relations for walking the result set: `first`, and `prev`\nand `next` where they exist. Present on every response from the lead\nlist, whether or not you asked for a page, so paging is discoverable\nwithout reading this document.\n\nWalk until there is no `rel=\"next\"`. There is deliberately no\n`rel=\"last\"` - knowing it would mean counting the whole matching set on\nevery request.\n",
        "schema": {
          "type": "string"
        },
        "example": "<https://app.retailleadmanagement.com/api/v1/pipeline/0123456789abcdef0123456789abcdef/leads/closed?page%5Bnumber%5D=1&page%5Bsize%5D=200>; rel=\"first\", <https://app.retailleadmanagement.com/api/v1/pipeline/0123456789abcdef0123456789abcdef/leads/closed?page%5Bnumber%5D=3&page%5Bsize%5D=200>; rel=\"next\""
      }
    },
    "responses": {
      "BadRequest": {
        "description": "The request could not be fulfilled. v1 returns this single code for all\nfailures, including bad credentials, an unknown pipeline key, and a lead\nthat does not exist or is not visible to the user.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Rate limit exceeded - more than 20 requests per second from your IP, or\nfrom your credentials. Retry after the number of seconds given in the\n`Retry-After` header.\n",
        "headers": {
          "Retry-After": {
            "description": "Seconds to wait before retrying.",
            "schema": {
              "type": "integer"
            }
          }
        }
      },
      "LeadNotFound": {
        "description": "No lead was returned for that id. The body is an HTML error page,\n**not** the JSON envelope - do not try to parse it as JSON.\n",
        "content": {
          "text/html": {
            "schema": {
              "type": "string"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "result": {
            "type": "string",
            "example": "Bad Request"
          },
          "messages": {
            "type": "string",
            "description": "A short explanation, when one is available.",
            "example": "No organization match found."
          }
        }
      },
      "Organization": {
        "type": "object",
        "description": "The parent object for pipelines, leads, tasks and users.\n",
        "properties": {
          "result": {
            "type": "string",
            "enum": [
              "Success"
            ]
          },
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "daily_agenda_delivery": {
            "type": "string",
            "format": "date-time",
            "description": "When the daily agenda email goes out. Only the time of day is\nmeaningful, but the value is a full ISO 8601 timestamp on a dummy\ndate - `2000-01-01T04:30:00.000-05:00` for a 9:30 a.m. delivery -\nand the offset is the application's, not your organization's. Read\nthe time of day from it and ignore the date.\n"
          },
          "daily_stalled_delivery": {
            "type": "string",
            "format": "date-time",
            "description": "When the daily stalled-lead email goes out. Same shape as\n`daily_agenda_delivery`: a dummy date, a real time of day, and the\napplication's offset rather than your organization's.\n"
          },
          "locations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Location"
            }
          },
          "divisions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Division"
            }
          },
          "pipelines": {
            "type": "array",
            "description": "Every pipeline in the organization. Note that pipeline API keys are\n**not** included - use `id` and `name` to identify a pipeline, and\nask RLM support for its key.\n",
            "items": {
              "$ref": "#/components/schemas/PipelineSummary"
            }
          }
        }
      },
      "PipelineSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "has_samples": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether the samples module is active for this pipeline. `null` on a\npipeline that has never had it configured either way - treat that\nas false.\n"
          },
          "sample_fields": {
            "type": "array",
            "nullable": true,
            "description": "`null` rather than `[]` when the pipeline has no sample fields,\nwhich is the usual case.\n",
            "items": {
              "type": "string"
            }
          },
          "default_division_id": {
            "type": "integer",
            "nullable": true,
            "description": "Division assigned to leads created via the API."
          },
          "default_location_id": {
            "type": "integer",
            "nullable": true,
            "description": "Location assigned to leads created via the API."
          },
          "default_salesperson_id": {
            "type": "integer",
            "nullable": true,
            "description": "Salesperson assigned to leads created via the API."
          }
        }
      },
      "Pipeline": {
        "type": "object",
        "description": "A pipeline and its full configuration. Pipelines are customised per\ncustomer, so the field list differs between organizations and between\npipelines within one organization.\n",
        "properties": {
          "result": {
            "type": "string",
            "enum": [
              "Success"
            ]
          },
          "name": {
            "type": "string"
          },
          "api_key": {
            "type": "string",
            "nullable": true,
            "description": "**Almost always `null`, and never the key you authenticated with.**\nThis is a legacy column that predates the current pipeline-key\nstorage; pipelines whose keys were issued the modern way have\nnothing in it. Do not treat it as a credential you can read back -\nkeep the key you were given.\n"
          },
          "has_samples": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether the samples module is active. `null` when it has never been\nconfigured either way - treat that as false.\n"
          },
          "sample_fields": {
            "type": "array",
            "nullable": true,
            "description": "`null` rather than `[]` when the pipeline has no sample fields.\n",
            "items": {
              "type": "string"
            }
          },
          "default_division_id": {
            "type": "integer",
            "nullable": true
          },
          "default_location_id": {
            "type": "integer",
            "nullable": true
          },
          "default_salesperson_id": {
            "type": "integer",
            "nullable": true
          },
          "pipeline_fields": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PipelineField"
            }
          },
          "pipeline_statuses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LeadStatus"
            }
          },
          "locations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Location"
            }
          },
          "divisions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Division"
            }
          }
        }
      },
      "PipelineField": {
        "type": "object",
        "description": "One data field on the lead object. Only active fields are returned.\n\nEach entry here is one field in the pipeline's setup. If you are looking\nat the same pipeline in RLM, this is the **Fields** tab of the pipeline's\ndetail page: one tile per field, captioned `Display Name (id)` with\n`column_name (type)` beneath it, opening a settings panel when clicked.\nThe table below says which box on that panel each key comes from.\n\n| Key here | In RLM |\n| --- | --- |\n| `display_name` | **Display Name** |\n| `column_name` | The line beneath the field's caption on its tile, and the title of its settings panel (`4821: source_name`). An editable **Column Name** box appears only on JSON-storage fields and on calculation fields with no lead column behind them. |\n| `api_field_name` | **API Field Name**. Shown only on pipelines that have API access. |\n| `field_type` | **Type** |\n| `field_options` | **Options** |\n| `required` | The **Required** checkbox |\n| `helper_text` | **Helper Text** |\n\nThat panel is an internal one and is not reachable from a customer\nlogin. An integrator should read these values out of the response; the\nscreen references are here so that you and whoever you ask at RLM are\ndescribing the same thing.\n",
        "properties": {
          "id": {
            "type": "integer",
            "description": "RLM's internal id for this field. It appears in parentheses after\nthe field's name on its tile, and before the colon in the title of\nits settings panel - quote it when asking support about a specific\nfield.\n"
          },
          "active": {
            "type": "boolean"
          },
          "required": {
            "type": "boolean"
          },
          "display_name": {
            "type": "string",
            "description": "The field's label as everyone using RLM sees it - on the lead form,\nin list columns, and in reporting. `Lead Source`, `How Heard`,\n`Products Interested In`.\n\n**This is not the key to send or read data under**, and the two\ndiffer routinely: the field labelled `Lead Source` carries its value\nunder `source_name`, and `Digital Channel` under `channel_utm`. Use\n`column_name` for that, and treat `display_name` as the thing to say\nout loud when you and RLM support need to agree on which field you\nmean.\n\nIt is also editable, so it is not a stable key: a pipeline that\nrenames `Lead Source` to `Where From` changes this value and nothing\nelse.\n"
          },
          "column_name": {
            "type": "string",
            "description": "**The name this field's data travels under.** A lead object always\ncarries this key, and it is the key `POST /api/{apiKey}/leads`\nwrites through unless the field also has an `api_field_name`. Match\non it when mapping RLM fields to your own system.\n\nIt is set when the field is created and is normally fixed\nthereafter, so it is safe to hard-code once you have read it -\nunlike `display_name`, which anyone administering the pipeline can\nrename at will.\n\nIn RLM it is the line beneath the field's caption on the **Fields**\ntab, and the part of its settings-panel title after the colon:\n`4821: source_name` is `source_name`. It is shown on every field but\neditable on almost none - the **Column Name** box only appears on\nJSON-storage fields and on calculation fields with no lead column\nbehind them.\n"
          },
          "api_field_name": {
            "type": "string",
            "nullable": true,
            "description": "**An optional second name for the same field**, so a pipeline can\naccept whatever key your system already sends without renaming\nanything in RLM. `null` on most fields of most pipelines: somebody\nhas to type it in deliberately, and almost nobody has.\n\nWhen one is set, a lead object carries the value under **both**\n`column_name` and `api_field_name`, and `POST /api/{apiKey}/leads`\ntries this name before falling back to `column_name`. When it is\n`null`, `column_name` is the only key that works.\n\nIn RLM it is the **API Field Name** box on the field's settings\npanel. The box is only rendered on pipelines that have API access,\nso on a pipeline where it is missing the answer is always\n`column_name`. Asking support to set one is how you get RLM to\naccept a key it currently drops into the lead's note.\n"
          },
          "field_type": {
            "type": "string",
            "description": "The kind of data the field holds - the **Type** dropdown on the\nfield's settings panel. This list is fixed in RLM's code and is the\nwhole of it; a value outside it cannot appear.\n\nHandle all of them. `calculation` is the one worth knowing about:\nthose fields are computed by RLM rather than entered, so their value\nis read-only in practice even though nothing marks it as such.\n\nNote also that a lead carries keys that are **not** in\n`pipeline_fields[]` at all - `stage_name`, `status_color`,\n`next_task_type` and the other status and task summaries listed on\n`Lead`. They are derived from the lead's status and next task rather\nthan from a configured field, so do not expect to find them here,\nand do not treat `pipeline_fields[]` as the complete key list for a\nlead. It is the complete list of *configurable* keys.\n\nThree types constrain what their value may be:\n\n- `select` - one value from the field's `field_options`.\n- `multiple_select` - any number of values from `field_options`,\n  comma-joined into a single string on a lead.\n- `state` - a US state or territory. Unlike the other two, the\n  permitted values are fixed rather than configured; they are\n  listed on `LeadCreate.state`.\n",
            "enum": [
              "address",
              "asterisk",
              "calculation",
              "checkbox",
              "currency",
              "date",
              "datetime",
              "email",
              "multiple_select",
              "number",
              "percentage",
              "phone_ext",
              "phone",
              "pound",
              "salesperson",
              "select",
              "state",
              "system",
              "text",
              "text_box",
              "time",
              "url",
              "user"
            ]
          },
          "field_options": {
            "type": "array",
            "nullable": true,
            "description": "**The values a `select` or `multiple_select` field offers.** This\nresponse is the only place the API publishes them, so read them from\nhere rather than hard-coding - a pipeline that adds a lead source or\na product line will not tell you.\n\n**`null`, not `[]`, when the field has no options** - which is the\ncase for every field of another type, and for a `select` field\nnobody has configured yet. Treat `null` and `[]` alike.\n\nMostly these are the account's own, edited per field per pipeline on\nthe **Options** list of the field's settings panel, so two pipelines\nin one organization can offer different sets. Two standard fields\nare the exception: `lead_type` and `channel_utm` have their values\nlocked by RLM and cannot be added to, removed from or reordered, so\nthose two *are* safe to code against.\n\n**This list also contains the field's discontinued options.** RLM\nkeeps retired values in a second **Discontinued Options** list so\nexisting leads still display them, and the web app hides them from\nnew entries - but the API returns one merged array and does not mark\nwhich is which. So `field_options` is the right list for *reading*\nhistorical data and slightly too permissive for *writing*: a value\nin it may be one RLM would no longer offer a user. Ask support which\nare current if it matters.\n\nNothing on the write side enforces any of this. `Lead` has no\ninclusion validation, so `POST /api/{apiKey}/leads` stores an\noff-list value exactly as sent and it surfaces as an unrecognised\nentry in reporting. Sending a value from this list is your\nresponsibility, not something the API will check.\n",
            "items": {
              "type": "string"
            }
          },
          "helper_text": {
            "type": "string",
            "nullable": true
          },
          "visiblity": {
            "type": "object",
            "description": "Where the field is shown in the web app. Note the spelling of this\nkey - it is `visiblity` in the response, and correcting it would\nbreak existing consumers.\n",
            "properties": {
              "new": {
                "type": "boolean"
              },
              "show": {
                "type": "boolean"
              },
              "edit": {
                "type": "boolean"
              },
              "listing": {
                "type": "boolean"
              },
              "task_listing": {
                "type": "boolean"
              },
              "sample_listing": {
                "type": "boolean"
              }
            }
          },
          "column": {
            "type": "integer",
            "description": "Column position on the new, detail and show pages."
          },
          "column_sort": {
            "type": "integer",
            "description": "Sort position within the column."
          }
        }
      },
      "LeadStatus": {
        "type": "object",
        "description": "A status controls a lead's progress through the sales process. Every\nstatus is either open or closed.\n\n**Statuses are configured per pipeline**, on the **Stages** tab of the\npipeline's detail page, so there is no fixed list to code against.\n`pipeline_statuses[]` on this response is the full set for this pipeline\nand the only place the API publishes it. A new pipeline starts with a\nstandard set whose initial status is `New`, but the names, the order and\nwhich of them count as closed are all the account's to change.\n\nThis is the list to check a lead's `stage_name` against, and the list to\noffer if you are building a status picker of your own.\n",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string",
            "description": "The status name as it appears in RLM and in a lead's `stage_name` -\n`New`, `Sold`, `Follow Up`. Compare on this string; there is no\nstable code behind it.\n"
          },
          "closed": {
            "type": "boolean",
            "description": "Whether a lead in this status counts as closed. This is what the\n`closed` and `all` values of `{status}` on **List leads** select on,\nand what a lead's `status` (`Open` / `Closed`) reports.\n"
          },
          "order": {
            "type": "integer"
          },
          "field_set": {
            "type": "array",
            "nullable": true,
            "description": "Fields displayed on the task tray for this status, by\n`column_name`. `null` rather than `[]` when the status has no task\ntray fields configured.\n",
            "items": {
              "type": "string"
            }
          },
          "task_types": {
            "type": "array",
            "description": "Task types selectable on the task tray for this status, by name.\nAlso configured per account rather than fixed - this array and\n`required_task` are the only list of them the API publishes.\n",
            "items": {
              "type": "string"
            }
          },
          "required_task": {
            "type": "string",
            "nullable": true,
            "description": "Name of the task type RLM requires when a lead enters this status,\nor `null` if none. Always one of the names in `task_types` when set.\n"
          }
        }
      },
      "Location": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "location_number": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "Division": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          }
        }
      },
      "Lead": {
        "type": "object",
        "description": "A lead as returned by the read endpoints.\n\n**This object carries additional keys beyond those listed here.** Every\nactive non-system field configured on the pipeline is included, keyed by\nits `column_name` and, when one is set, also by its `api_field_name`.\nFields of type `phone` *and* `phone_ext` additionally appear as\n`<column_name>_e164` holding the E.164-normalised number. Read\n`GET /api/v1/pipeline/{apiKey}` to discover which extra keys a given\npipeline produces.\n\nValues are rendered for display - dates are formatted strings, currency\nis formatted, and multi-selects are comma-joined - rather than returned\nas raw database values.\n\nNote that the shape here is not the shape accepted by\n`POST /api/{apiKey}/leads`; see `LeadCreate`.\n",
        "additionalProperties": true,
        "properties": {
          "id": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "Open",
              "Closed"
            ]
          },
          "name": {
            "type": "string",
            "description": "Display name of the lead."
          },
          "pipeline": {
            "type": "string",
            "description": "Name of the pipeline the lead is in. One of the `pipelines[].name`\nvalues from `GET /api/v1/organization`.\n"
          },
          "location_name": {
            "type": "string",
            "description": "Name of the dealer store location the lead is filed under. One of\nthe `locations[].name` values from `GET /api/v1/pipeline/{apiKey}`,\nwhich is also where you find its `location_id`. Configured per\npipeline, so there is no fixed list.\n"
          },
          "location": {
            "type": "string",
            "description": "Alias of `location_name`."
          },
          "division_name": {
            "type": "string",
            "description": "Name of the sales division the lead is filed under. One of the\n`divisions[].name` values from `GET /api/v1/pipeline/{apiKey}`,\nwhich is also where you find its `division_id`. Configured per\npipeline, so there is no fixed list.\n"
          },
          "division": {
            "type": "string",
            "description": "Alias of `division_name`."
          },
          "salesperson": {
            "type": "string",
            "nullable": true,
            "description": "Display name of the assigned salesperson, and `null` while nobody\nis assigned - which is how every lead created through\n`POST /api/{apiKey}/leads` starts life. Test `unassigned` rather\nthan inferring ownership from this field.\n"
          },
          "stage_name": {
            "type": "string",
            "description": "The lead's current status name. One of the `pipeline_statuses[].name`\nvalues from `GET /api/v1/pipeline/{apiKey}` - configured per\npipeline, so read that list rather than assuming a fixed set. Also\nthe value to filter on with `rlm_filters[stage_name]` if you move to\nthe v3 API.\n"
          },
          "stage_class": {
            "type": "string",
            "nullable": true,
            "description": "A CSS-safe form of `stage_name` - the status name lower-cased and\nhyphenated, so `Follow Up` becomes `follow-up`. It therefore varies\nwith the pipeline's configured statuses exactly as `stage_name`\ndoes.\n\nA lead still sitting in the pipeline's initial status is the\nexception: it reports its assignment state instead, as one of\n`unassigned`, `assigned` or `accepted`.\n"
          },
          "status_color": {
            "type": "string",
            "nullable": true,
            "description": "The colour RLM shows the lead's status badge in, or `null` when the\nlead's stage has no colour configured. One of a fixed set\nof 21 colour names - no endpoint publishes it, so here it is:\n\n`red` `pink` `purple` `deep-purple` `indigo` `blue` `light-blue`\n`cyan` `teal` `green` `light-green` `lime` `yellow` `amber`\n`orange` `deep-orange` `brown` `grey` `blue-grey` `black` `white`\n\nWhich colour belongs to which status is set per pipeline, so the\nmapping is not fixed even though the palette is.\n\nAs with `stage_class`, a lead in the pipeline's initial status\nreports `unassigned`, `assigned` or `accepted` here instead of a\ncolour - so branch on those three before treating the value as one.\n",
            "enum": [
              "red",
              "pink",
              "purple",
              "deep-purple",
              "indigo",
              "blue",
              "light-blue",
              "cyan",
              "teal",
              "green",
              "light-green",
              "lime",
              "yellow",
              "amber",
              "orange",
              "deep-orange",
              "brown",
              "grey",
              "blue-grey",
              "black",
              "white",
              "unassigned",
              "assigned",
              "accepted"
            ]
          },
          "next_task_type": {
            "type": "string",
            "description": "Name of the task type on the lead's next task. Present only when the\nlead has an upcoming task.\n\nTask types are configured per account, not fixed. The only list the\nAPI publishes is `pipeline_statuses[].task_types` on\n`GET /api/v1/pipeline/{apiKey}`, which gives the types selectable at\neach status.\n"
          },
          "next_task_regarding": {
            "type": "string"
          },
          "next_task_name": {
            "type": "string",
            "description": "Alias of `next_task_regarding`."
          },
          "task_start_date": {
            "type": "string"
          },
          "lead_task_start_date": {
            "type": "string",
            "description": "Alias of `task_start_date`."
          },
          "next_task_overdue": {
            "type": "boolean",
            "description": "Whether that next task is past due. A real JSON boolean, not the\n`\"Yes\"`/`\"No\"` string that `samples_out` uses - the two are\ninconsistent, and this is the one that is a boolean. Present only\nwhen the lead has an upcoming task.\n"
          },
          "next_task_start_time": {
            "type": "string"
          },
          "next_task_end_time": {
            "type": "string"
          },
          "samples_out": {
            "type": "string",
            "enum": [
              "Yes",
              "No"
            ],
            "description": "Whether the lead has samples checked out. A **string**, not a\nboolean - always exactly `\"Yes\"` or `\"No\"`.\n"
          },
          "external_lead_source": {
            "type": "string",
            "nullable": true
          },
          "external_lead_id": {
            "type": "string",
            "nullable": true
          },
          "external_lead_key": {
            "type": "string",
            "nullable": true
          },
          "pipeline_api_key": {
            "type": "string",
            "nullable": true,
            "description": "The pipeline API key the lead was created through, when it was\ncreated via the API.\n"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "closed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "sold_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "lead_created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Alias of `created_at`."
          },
          "lead_updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Alias of `updated_at`."
          },
          "lead_closed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Alias of `closed_at`."
          },
          "created_by": {
            "type": "string",
            "nullable": true
          },
          "updated_by": {
            "type": "string",
            "nullable": true
          },
          "lead_created_by": {
            "type": "string",
            "nullable": true,
            "description": "Alias of `created_by`."
          },
          "lead_updated_by": {
            "type": "string",
            "nullable": true,
            "description": "Alias of `updated_by`."
          },
          "time_to_sale": {
            "type": "string",
            "nullable": true,
            "description": "Elapsed time to sale, in words."
          },
          "time_to_contact": {
            "type": "string",
            "nullable": true,
            "description": "Elapsed time to first contact, in words."
          },
          "organization_id": {
            "type": "integer"
          },
          "pipeline_id": {
            "type": "integer"
          },
          "location_id": {
            "type": "integer",
            "nullable": true
          },
          "division_id": {
            "type": "integer",
            "nullable": true
          },
          "salesperson_id": {
            "type": "integer",
            "nullable": true
          },
          "stage_id": {
            "type": "integer",
            "nullable": true
          },
          "company_id": {
            "type": "integer",
            "nullable": true
          },
          "contact_id": {
            "type": "integer",
            "nullable": true
          },
          "open": {
            "type": "boolean"
          },
          "pending": {
            "type": "boolean",
            "description": "The lead is new and has not yet been worked."
          },
          "unassigned": {
            "type": "boolean"
          },
          "deleted": {
            "type": "boolean"
          }
        }
      },
      "LeadCreate": {
        "type": "object",
        "description": "The payload accepted by `POST /api/{apiKey}/leads`.\n\nA key is written to a pipeline field when it matches that field's\n`api_field_name`, and otherwise when it matches the field's\n`column_name`. `api_field_name` is an alias that has to be configured\nper field and usually is not, so `column_name` is the key that works on\nmost pipelines.\n\nUnmatched keys are collected into a note on the new lead rather than\nbeing rejected, so a slightly wrong key name fails quietly - verify\nagainst `GET /api/v1/pipeline/{apiKey}` rather than assuming a field\nlanded.\n",
        "additionalProperties": true,
        "properties": {
          "location_name": {
            "type": "string",
            "description": "Dealer store location, looked up by name among the pipeline's\nlocations.\n\n**An unrecognised name is not an error.** The lead is filed under\nthe pipeline's default location instead, or under the\nalphabetically first location if the pipeline has no default, and\nthe response is still `201`. A misspelled store name therefore\nbooks the lead at the wrong branch in silence, so read `location`\nback from the created lead rather than trusting the name you sent.\nOmitting the key falls back the same way.\n\nSending a numeric `location_id` avoids the guesswork: it is used\nas-is when it belongs to this pipeline, and ignored - falling back\nto the behaviour above - when it does not. `division_id` works the\nsame way for divisions.\n\nBoth ids are listed in `locations[]` and `divisions[]` on\n`GET /api/v1/pipeline/{apiKey}`.\n"
          },
          "division_name": {
            "type": "string",
            "description": "Dealer sales division, looked up by name among the pipeline's\ndivisions.\n\n**An unrecognised name is not an error.** The lead is filed under\nthe pipeline's default division instead, or under the\nalphabetically first division if the pipeline has no default, and\nthe response is still `201`. A misspelled division name therefore\nbooks the lead against the wrong division in silence, so read\n`division` back from the created lead rather than trusting the name\nyou sent. Omitting the key falls back the same way.\n\nSending a numeric `division_id` avoids the guesswork: it is used\nas-is when it belongs to this pipeline, and ignored - falling back\nto the behaviour above - when it does not. `location_id` works the\nsame way for locations.\n\nBoth ids are listed in `divisions[]` and `locations[]` on\n`GET /api/v1/pipeline/{apiKey}`.\n"
          },
          "source_name": {
            "type": "string",
            "description": "Lead source - labelled **Lead Source** in RLM. Defaults to `Website`\nwhen omitted.\n\nA `select` field, so its permitted values are configured per\npipeline: read `field_options` for the `source_name` entry in\n`pipeline_fields[]` on `GET /api/v1/pipeline/{apiKey}`. New\npipelines start from a standard list, but accounts edit it, so the\nvalues on the pipeline you are posting to are the only ones that\ncount. Nothing validates what you send - an off-list value is\nstored as sent and shows up as an unrecognised entry in reporting.\n",
            "example": "Website"
          },
          "channel_name": {
            "type": "string",
            "description": "A channel within the lead source - labelled **Lead Channel** in RLM.\n\nA `select` field, so its permitted values are configured per\npipeline: read `field_options` for the `channel_name` entry in\n`pipeline_fields[]` on `GET /api/v1/pipeline/{apiKey}` and send one\nof those. Unlike `source_name`, RLM ships this field with no options\nat all, so a pipeline that has never had any configured accepts\nanything and means nothing by it.\n\nNot validated either way - `Lead` has no inclusion validation, so an\noff-list value is stored exactly as sent and shows up as an\nunrecognised entry in reporting.\n"
          },
          "company_name": {
            "type": "string"
          },
          "first_name": {
            "type": "string"
          },
          "last_name": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "website": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "mobile_phone": {
            "type": "string"
          },
          "work_phone": {
            "type": "string"
          },
          "work_phone_ext": {
            "type": "string"
          },
          "address1": {
            "type": "string"
          },
          "address2": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "state": {
            "type": "string",
            "description": "State or territory. **Send the two-letter code.**\n\nUnlike `select` fields, whose values are configured per pipeline,\nthe values a `state` field accepts are fixed in RLM and identical\neverywhere - the 50 states plus DC, five territories, one outlying\ngroup, and the three military mailing codes:\n\n`AL` `AK` `AZ` `AR` `CA` `CO` `CT` `DE` `DC` `FL` `GA` `HI` `ID`\n`IL` `IN` `IA` `KS` `KY` `LA` `ME` `MD` `MA` `MI` `MN` `MS` `MO`\n`MT` `NE` `NV` `NH` `NJ` `NM` `NY` `NC` `ND` `OH` `OK` `OR` `PA`\n`RI` `SC` `SD` `TN` `TX` `UT` `VT` `VA` `WA` `WV` `WI` `WY` -\n`AS` `GU` `MP` `PR` `UM` `VI` - `AA` `AE` `AP`\n\nThat is 60 values in total. It is the whole of what RLM's own state\npickers offer and the whole of what the name-to-code conversion\nbelow will match; Canadian provinces are **not** among them, so a\nvalue like `ON` is simply stored verbatim.\n\n**Sending a full state name usually does not work.** A name such as\n`California` is converted to `CA` only when the pipeline's state\nfield has an `api_field_name` and your key matched *that* name.\nWhen the key matched by `column_name` - the usual case, since\n`api_field_name` is rarely configured - no conversion happens at\nall and `California` is stored as `California`. Sending the code\navoids the distinction entirely, because a code needs no\nconversion.\n\nNothing rejects an unrecognised value; it is stored as sent. Read\nthe field back from the created lead if it matters.\n",
            "x-recognised-values": [
              "AL",
              "AK",
              "AZ",
              "AR",
              "CA",
              "CO",
              "CT",
              "DE",
              "DC",
              "FL",
              "GA",
              "HI",
              "ID",
              "IL",
              "IN",
              "IA",
              "KS",
              "KY",
              "LA",
              "ME",
              "MD",
              "MA",
              "MI",
              "MN",
              "MS",
              "MO",
              "MT",
              "NE",
              "NV",
              "NH",
              "NJ",
              "NM",
              "NY",
              "NC",
              "ND",
              "OH",
              "OK",
              "OR",
              "PA",
              "RI",
              "SC",
              "SD",
              "TN",
              "TX",
              "UT",
              "VT",
              "VA",
              "WA",
              "WV",
              "WI",
              "WY",
              "AS",
              "GU",
              "MP",
              "PR",
              "UM",
              "VI",
              "AA",
              "AE",
              "AP"
            ]
          },
          "zip": {
            "type": "string"
          },
          "deal_name": {
            "type": "string"
          },
          "how_heard": {
            "type": "string",
            "description": "How the customer heard about the dealer, and the current standard\nfield for it - every pipeline RLM sets up now gets this one.\n\nA `select` field: read `field_options` for the `how_heard` entry in\n`pipeline_fields[]` on `GET /api/v1/pipeline/{apiKey}` and send one\nof those values. RLM seeds a starting list, but accounts edit it, so\nonly the pipeline's own list counts. Nothing validates what you send\n- `Lead` has no inclusion validation - so an off-list value is\nstored exactly as sent and shows up as an unrecognised entry in\nreporting.\n\n**\"How Heard\" on screen does not reliably mean this field.** See\n`referral_type`.\n"
          },
          "referral_type": {
            "type": "string",
            "description": "The **older** how-heard field, and the reason to map these two by\n`column_name` rather than by what the screen says.\n\nRLM no longer configures `referral_type` on new pipelines. On\npipelines that predate `how_heard` it is still there and still\nlabelled **How Heard** - and when `how_heard` was added alongside\nit, the *new* field was the one relabelled, to **How Heard (Unified\nLeads)**. So on an older pipeline the field captioned \"How Heard\" is\n`referral_type`, and on a newer one it is `how_heard`. Read\n`pipeline_fields[]` and match on `column_name` to see which this\npipeline has; do not infer it from the label.\n\nWhere the field is configured it is a `select`, and the usual rule\napplies: read its `field_options` from\n`GET /api/v1/pipeline/{apiKey}` and send one of those values.\n\nSending it where it is *not* configured fails quietly rather than\nloudly. `referral_type` is a column on every lead, so the value is\nstored and you get `201` - but with no field configured for it,\nnothing shows it in the web app and no read returns it, because\nreads only cover the pipeline's configured fields.\n"
          },
          "referral_source": {
            "type": "string"
          },
          "products_interested_in": {
            "type": "array",
            "description": "Product lines - labelled **Products Interested In** in RLM.\n\nA `multiple_select` field, so send several values as an array and\neach must come from the same configured list: read `field_options`\nfor the `products_interested_in` entry in `pipeline_fields[]` on\n`GET /api/v1/pipeline/{apiKey}`. On a lead read back, the values\narrive comma-joined into one string rather than as an array.\n\nThe example below is illustrative only - the real list is whatever\nthat pipeline has configured. As with `referral_type` and\n`promo_type`, nothing validates it and off-list values are stored as\nsent.\n",
            "items": {
              "type": "string"
            },
            "example": [
              "carpet",
              "hardwood",
              "tile"
            ]
          },
          "opt_in": {
            "type": "boolean",
            "description": "Email marketing permission."
          },
          "promo_type": {
            "type": "string",
            "description": "Which promotion the lead came in under - labelled **Promo Type** in\nRLM.\n\nA `select` field: read `field_options` for the `promo_type` entry in\n`pipeline_fields[]` on `GET /api/v1/pipeline/{apiKey}`. RLM ships\nthis field with no options, so anything it offers is entirely the\naccount's own list.\n\nNothing validates this against the pipeline's configured options -\n`Lead` has no inclusion validation - so an off-list value is stored\nexactly as sent and shows up as an unrecognised entry in reporting.\nRead the field's `field_options` from\n`GET /api/v1/pipeline/{apiKey}` and send one of those values.\n"
          },
          "note": {
            "type": "string",
            "description": "Initial comments or request detail."
          }
        }
      }
    }
  }
}