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

# List available lines

> Lists the lines that can be acquired now, with masked phone numbers.

* **Credential:** none. The operation ignores any credential, and phone numbers are masked for every caller. See [The marketplace](/guides/getting-a-line#the-marketplace).
* **Events:** none.
* **What is listed:** only lines that can be acquired now. A line can leave the list and come back, so read the list again before each reservation.
* **Pagination:** by page number, with `page` and `limit`. This list does not use the cursors of the [other list operations](/pagination#list-operations).
* **Metadata:** each line carries its `metadata`, which can hold keys that an earlier owner left. The query parameter `metadata.<key>=<value>` keeps the lines whose `metadata` holds exactly that string under that key. Anyone can use this filter, without a credential: never put personal data or secrets in line `metadata`. See [Metadata at acquisition](/guides/getting-a-line#metadata-at-acquisition).

## Errors

| Status | `error.code` | When |
| - | - | - |
| 400 | `validation_failed` | `status` is not `available`; `page` is not an integer of at least 1; `limit` is not 1 to 100; `country_code` is not 2 characters; `area_code` is longer than 10 characters; `state` is not 2 to 40 characters; `country` is not 2 to 60 characters; or `billing_tier` is not a known value. |

The errors that every operation shares are in [Errors](/errors-and-rate-limits#errors).


## OpenAPI

````yaml GET /v1/lines
openapi: 3.0.0
info:
  title: iSnap API
  version: 2.45.0
  description: >-
    The iSnap API sends and receives iMessage, RCS and SMS on real phone lines,
    manages those lines, and reports events through webhooks. Every message is
    sent to a real recipient, with an `isnap_live_` key and with an
    `isnap_test_` key alike. Retry a `429` after `Retry-After` seconds. Retry a
    `500` or a `503` up to 2 times, with exponential backoff. Do not retry any
    other `4xx`: fix the request. Retry a write only on an operation that honors
    `Idempotency-Key`, with the key of the first attempt. Responses carry
    personal data: handles, names and message text.
servers:
  - url: https://api.isnap.ai
security:
  - bearerAuth: []
paths:
  /v1/lines:
    get:
      summary: List available lines
      description: >-
        Lists the marketplace: the lines that can be acquired now. Needs no
        credential, and ignores one: phone numbers are masked for every caller.


        Only lines that are `available` and ready to send are listed, so a line
        can leave the list and come back without being acquired: read the list
        again before you reserve or assign. Shared lines, test lines and
        dedicated pool lines are never listed. Each item is the full line
        object, `metadata` included.


        Besides the declared filters, a query parameter `metadata.<key>=<value>`
        keeps the lines whose `metadata` holds exactly that string under that
        key; when a key is repeated, its first value applies. Lines are ordered
        by `area_code` then `phone_number` and paged with `page` and `limit`.
        Request the next `page` while `page` times `limit` is below `total`.
      parameters:
        - schema:
            type: string
            enum:
              - rental_iphone
              - rental_android
              - byod_imessage
              - byod_android
              - shared_pool
              - shared_imessage
            description: >-
              Keep the lines of one kind: `rental_iphone`, `rental_android`,
              `byod_imessage` or `byod_android`. `shared_pool` and
              `shared_imessage` are accepted and always return an empty list:
              shared lines, test lines and dedicated pool lines are never
              listed.
          required: false
          description: >-
            Keep the lines of one kind: `rental_iphone`, `rental_android`,
            `byod_imessage` or `byod_android`. `shared_pool` and
            `shared_imessage` are accepted and always return an empty list:
            shared lines, test lines and dedicated pool lines are never listed.
          name: billing_tier
          in: query
        - schema:
            type: string
            maxLength: 10
            description: >-
              Keep the lines whose `area_code` is exactly this value, a 3-digit
              North American area code.
          required: false
          description: >-
            Keep the lines whose `area_code` is exactly this value, a 3-digit
            North American area code.
          name: area_code
          in: query
        - schema:
            type: string
            minLength: 2
            maxLength: 2
            description: >-
              Keep the lines of one country: ISO 3166-1 alpha-2 code,
              case-insensitive.
          required: false
          description: >-
            Keep the lines of one country: ISO 3166-1 alpha-2 code,
            case-insensitive.
          name: country_code
          in: query
        - schema:
            type: string
            minLength: 2
            maxLength: 40
            description: >-
              Keep the lines of one US state: its 2-letter code or its name,
              case-insensitive. An unknown state returns an empty list.
            example: California
          required: false
          description: >-
            Keep the lines of one US state: its 2-letter code or its name,
            case-insensitive. An unknown state returns an empty list.
          name: state
          in: query
        - schema:
            type: string
            minLength: 2
            maxLength: 60
            description: >-
              Keep the lines of one country: its ISO 3166-1 alpha-2 code or its
              name, case-insensitive. An unknown country returns an empty list.
            example: United States
          required: false
          description: >-
            Keep the lines of one country: its ISO 3166-1 alpha-2 code or its
            name, case-insensitive. An unknown country returns an empty list.
          name: country
          in: query
        - schema:
            type: string
            description: >-
              Accepts `available`, or an empty value: any other value returns
              `400 validation_failed`. The list holds `available` lines whether
              or not this parameter is sent.
            example: available
          required: false
          description: >-
            Accepts `available`, or an empty value: any other value returns `400
            validation_failed`. The list holds `available` lines whether or not
            this parameter is sent.
          name: status
          in: query
        - schema:
            type: integer
            minimum: 1
            default: 1
            description: Page number, starting at 1.
          required: false
          description: Page number, starting at 1.
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
            description: Number of lines per page, from 1 to 100.
          required: false
          description: Number of lines per page, from 1 to 100.
          name: limit
          in: query
      responses:
        '200':
          description: >-
            One page of available lines, with the number of lines that match the
            filters.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                    description: Always `true` on a success response.
                  data:
                    $ref: '#/components/schemas/LineList'
                  trace_id:
                    type: string
                    description: >-
                      Trace id of the request that produced this response: 32
                      lowercase hexadecimal characters. Quote it when you report
                      a problem to iSnap.
                  request_id:
                    type: string
                    description: >-
                      Id of the request that produced this response: `req_`
                      followed by 25 letters or digits.
                required:
                  - success
                  - data
                  - trace_id
                  - request_id
        '400':
          description: >-
            Invalid request. `validation_failed`: a query parameter does not
            match its schema, for example a `status` that is neither `available`
            nor empty, a `limit` above 100 or an unknown `billing_tier`.
            `error.issues` lists each problem.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '429':
          description: >-
            Too many requests. `error.code` is `rate_limit_exceeded` when more
            than 100 requests came from the same network address in 60 seconds,
            whatever their API key or account: wait `error.retry_after` seconds.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '500':
          description: >-
            Unexpected failure. `error.code` is `internal_error`. An operation
            that takes a JSON body also returns it when the body, sent as
            `application/json`, is not valid JSON. Quote `trace_id` when you
            report it to iSnap.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
      security: []
components:
  schemas:
    LineList:
      type: object
      properties:
        lines:
          type: array
          items:
            $ref: '#/components/schemas/Line'
          description: >-
            One page of available lines, ordered by `area_code` then
            `phone_number`, with masked phone numbers.
        total:
          type: integer
          minimum: 0
          description: Number of lines that match the filters, across all pages.
        page:
          type: integer
          minimum: 1
          description: The page returned.
        limit:
          type: integer
          minimum: 1
          maximum: 100
          description: The page size applied.
      required:
        - lines
        - total
        - page
        - limit
      description: One page of the marketplace.
    ErrorEnvelope:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - false
          description: Always `false` on an error response.
        data:
          nullable: true
          description: Always `null` on an error response.
        error:
          type: object
          properties:
            status:
              type: integer
              description: The HTTP status of the response.
            code:
              type: string
              description: >-
                Stable machine-readable code that names the refusal. Branch on
                this value.
            message:
              type: string
              description: >-
                Text for a person. It can change between versions: do not branch
                on it.
            retry_after:
              type: integer
              nullable: true
              description: >-
                Seconds to wait before the next attempt. Set on the `429`
                responses that know a delay, where the `Retry-After` header
                carries the same value. When it is above 60 seconds, do not wait
                in a request: schedule the call, or report the time. `null` on
                every other error.
            retry_at:
              type: string
              nullable: true
              description: >-
                ISO 8601 timestamp at which the refusal ends. Set only on `429
                rebind_cap_reached`. `null` on every other error.
            issues:
              type: array
              nullable: true
              items:
                type: object
                properties:
                  path:
                    type: array
                    items:
                      anyOf:
                        - type: string
                        - type: number
                    description: >-
                      Where the problem is: the field names and array indexes
                      that lead to it.
                  message:
                    type: string
                    description: Text for a person.
                  code:
                    type: string
                    description: >-
                      Kind of problem. On `validation_failed`, for example
                      `invalid_type`, `invalid_value`, `invalid_format`,
                      `invalid_union`, `invalid_key`, `invalid_element`,
                      `too_small`, `too_big`, `not_multiple_of`,
                      `unrecognized_keys` or `custom`. The list is open: read
                      `path` and `message`.
                  min:
                    type: integer
                    description: >-
                      Smallest accepted value. Present only on
                      `limit_out_of_bounds`, `mac_quantity_not_a_pack`,
                      `byop_reduction_strands_mac_sessions` and
                      `byop_reduction_strands_byod_lines`.
                  max:
                    type: integer
                    description: >-
                      Largest accepted value. Present only on
                      `limit_out_of_bounds` and
                      `mac_sessions_exceed_byop_lines`, and on the `too_big`
                      issue of an `Idempotency-Key` header longer than 255
                      characters.
                required:
                  - path
                  - message
                  - code
              description: >-
                Problems found in the request, one entry each. Set on most `400
                validation_failed` responses and on the refusals that name a
                field: a refused `handle` of `POST /v1/lookup` has `issues:
                null`. `null` on every other error.
          required:
            - status
            - code
            - message
            - retry_after
            - retry_at
            - issues
          description: >-
            What went wrong. The six fields are always present; `retry_after`,
            `retry_at` and `issues` are `null` when they do not apply.
        trace_id:
          type: string
          description: >-
            Trace id of the request that produced this response: 32 lowercase
            hexadecimal characters. Quote it when you report a problem to iSnap.
        request_id:
          type: string
          description: >-
            Id of the request that produced this response: `req_` followed by 25
            letters or digits.
      required:
        - success
        - data
        - error
        - trace_id
        - request_id
      description: The body of an error response.
    Line:
      type: object
      properties:
        id:
          type: string
          pattern: ^line_[0-9A-Za-z]{25}$
          description: 'Id of a line: `line_` followed by 25 letters or digits.'
        phone_number:
          type: string
          description: >-
            The phone number of the line in E.164 format. An empty string, never
            `null`, when the line has no number: a BYOD line whose device has
            not reported one, or a shared line. `GET /v1/attention` returns
            `null` for such a line. Masked on `GET /v1/lines`, and on `GET
            /v1/lines/{id}` unless the caller owns the line: `+1 (AAA) ***-**DD`
            for a North American number, the country code, asterisks and the
            last two digits for any other number.
        area_code:
          type: string
          nullable: true
          description: >-
            The 3-digit North American area code of the number. `null` for any
            other number, and while the number is not known.
        country_code:
          type: string
          nullable: true
          description: >-
            ISO 3166-1 alpha-2 country of the number. `null` while the number is
            not known.
        state:
          type: string
          nullable: true
          description: >-
            Two-letter code of the US state the area code belongs to. `null`
            outside the US, and while the number is not known.
        state_name:
          type: string
          nullable: true
          description: >-
            Name of that US state, for example `California`. `null` whenever
            `state` is `null`.
        billing_tier:
          type: string
          enum:
            - rental_iphone
            - rental_android
            - byod_imessage
            - byod_android
            - shared_pool
            - shared_imessage
          description: >-
            The kind of line. `rental_iphone`: a rented line that sends iMessage
            and SMS. `rental_android`: a rented line that sends SMS and RCS.
            `byod_imessage`: a BYOD line on your own Mac and iPhone.
            `byod_android`: a BYOD line on your own Android phone.
            `shared_imessage`: a shared line. `shared_pool`: a test line when
            `test_line` is `true`, otherwise a dedicated pool line: a line of
            iSnap that is dedicated to your account.
        byod:
          type: boolean
          description: >-
            `true` for a BYOD line, which runs on your own device:
            `billing_tier` is `byod_imessage` or `byod_android`.
        inbound_only:
          type: boolean
          description: >-
            `true` for an inbound-only line: it can message a contact only after
            that contact has messaged it. A send to any other handle returns
            `403 outbound_first_forbidden`. Only a rented line can be
            inbound-only: always `false` on BYOD, shared and test lines.
        capabilities:
          nullable: true
          description: >-
            The services the line sends, as an array of lowercase names:
            `["imessage", "sms"]` on `rental_iphone` and `byod_imessage` lines,
            `["sms", "rcs"]` on `rental_android` and `byod_android` lines,
            `["imessage"]` on a shared line. A test line that you made from a
            rented line keeps the array of that line. On a dedicated pool line,
            and on a test line that iSnap created for your account, the array
            does not tell the services and can be `["sms"]`: such a line is an
            iMessage line.
        status:
          type: string
          description: >-
            One of six values. `provisioning`: the line is being prepared for
            one of your pre-orders. `available`: the line belongs to no account
            and can be reserved or assigned. `reserved`: the line is reserved
            for one account until `expires_at`; it is not billed and cannot
            send. `active`: the line belongs to its owner; it is the only status
            in which a line sends. `suspended`: the line still belongs to its
            owner but cannot send (`403 line_suspended`); a line billed by a
            per-line subscription is suspended when a payment for it fails,
            iSnap can also suspend a line, and no API operation ends a
            suspension. `cancelled`: the line is ended for good and keeps its
            owner.
        monthly_price:
          type: integer
          minimum: 0
          deprecated: true
          description: >-
            Deprecated. Catalog price of this kind of line, in US cents. It is
            not the amount billed for the line. Removed in the next major
            version: no removal date is set.
        stripe_subscription_id:
          type: string
          nullable: true
          description: >-
            Id of the per-line subscription that bills the line. `null` on a
            line billed on the monthly wholesale invoice, on BYOD, shared and
            test lines, and on a rented line that a direct account received by
            transfer while the line was not `active`.
        activated_at:
          type: string
          nullable: true
          description: >-
            Timestamp at which the line became `active` (ISO 8601, UTC). `null`
            on a line that was never activated, and again on a line that
            returned to the marketplace. A transfer to a wholesale partner sets
            it to the time of the transfer; a transfer to a direct account keeps
            the earlier value.
        expires_at:
          type: string
          nullable: true
          description: >-
            End of the reservation (ISO 8601, UTC): 15 minutes after the line
            was reserved. Read it only while `status` is `reserved`: in any
            other status it is `null` or a past timestamp.
        anniversary_at:
          type: string
          nullable: true
          description: >-
            The anniversary of the line: the timestamp at which you took it (ISO
            8601, UTC). `POST /v1/lines/{id}/cancel` ends the line at the next
            occurrence of this timestamp. iSnap sets it each time a line becomes
            a wholesale partner's, a transfer included, and `POST
            /v1/lines/{id}/anniversary` replaces it. A conversion to a test line
            and back keeps it. `null` on a line owned by a direct account or by
            no account, and on a line of a wholesale partner whose anniversary
            was never set.
        cancel_at:
          type: string
          nullable: true
          description: >-
            Timestamp at which iSnap ends this line (ISO 8601, UTC). Set by
            `POST /v1/lines/{id}/cancel` and cleared by `POST
            /v1/lines/{id}/uncancel`. The line works and is billed as before
            until then. `null` when no end is scheduled. A line that ended at
            this date keeps the value. On a test line ended with `POST
            /v1/lines/{id}/terminate`, it holds the time the line ended.
        billing_anchor_at:
          type: string
          nullable: true
          description: >-
            The billing anchor you stated for this line (ISO 8601, UTC): a line
            billed on the monthly wholesale invoice is billed at each monthly
            occurrence of this timestamp. `null` when you stated none: the line
            is then billed at each monthly occurrence of `activated_at`. State
            it with `POST /v1/pre-orders`, `POST /v1/lines/{id}/activate` or
            `PATCH /v1/lines/{id}`. A change applies from the next occurrence
            and does not alter a month already billed.
        next_anchor_at:
          type: string
          nullable: true
          description: >-
            For a line billed on the monthly wholesale invoice: the next
            timestamp at which it is billed (ISO 8601, UTC). It is the next
            occurrence, strictly after the read, of `billing_anchor_at`, or of
            `activated_at` when no billing anchor is stated: the same day of the
            month, moved to the last day of a shorter month, at the same time of
            day. `null` when the line is not `active` or `suspended`, when it
            was never activated, and when its `cancel_at` falls on or before
            that occurrence. A line billed by a per-line subscription also
            carries a value here, which does not tell when that line is billed.
        pending_variant:
          type: object
          nullable: true
          properties:
            inbound_only:
              type: boolean
              description: The value `inbound_only` takes when the change applies.
            effective_at:
              type: string
              description: >-
                The billing anchor occurrence at which the change applies (ISO
                8601, UTC). iSnap applies it after this timestamp, and before it
                charges the line for the month that starts then: the API does
                not bound the delay.
          required:
            - inbound_only
            - effective_at
          description: >-
            The variant change scheduled for this line, or `null` when none is
            pending. The `inbound_only` field of the line keeps its value until
            the change applies. Schedule a change with `POST
            /v1/lines/{id}/variant` and `effective: "next_anchor"`; withdraw it
            with `DELETE /v1/lines/{id}/variant`. It becomes `null` when the
            change is applied, when it is withdrawn, when it can no longer apply
            at its date, when the line becomes a test line, and when the line
            leaves its owner without ending. A line that ends keeps its
            `pending_variant`, and the change never applies.
        created_at:
          type: string
          description: >-
            Timestamp at which iSnap created the line (ISO 8601, UTC). It is not
            the date you acquired the line.
        metadata:
          type: object
          nullable: true
          additionalProperties:
            nullable: true
          description: >-
            Your own key-value data on the line. `null` when the line has none.
            A line created with `"metadata": {}` reads `{}`: treat `null` and
            `{}` the same. It is part of the line object for every caller, `GET
            /v1/lines` and `GET /v1/lines/{id}` included, and a line that
            returns to the marketplace keeps it: never put personal data or
            secrets in it.
        test_line:
          type: boolean
          description: >-
            `true` for a test line: a line you set aside to host the trials of
            your own prospects. Its `billing_tier` is `shared_pool`.
        shared:
          type: boolean
          description: >-
            `true` for a shared line, which has no device and no phone number of
            its own: its `billing_tier` is `shared_imessage` and its
            `phone_number` is an empty string.
        fulfillment_status:
          type: string
          nullable: true
          description: >-
            Present only on `GET /v1/lines/my`. `open` while an order for this
            line is still being fulfilled, `null` otherwise.
      required:
        - id
        - phone_number
        - area_code
        - country_code
        - state
        - state_name
        - billing_tier
        - byod
        - inbound_only
        - status
        - monthly_price
        - stripe_subscription_id
        - activated_at
        - expires_at
        - anniversary_at
        - cancel_at
        - billing_anchor_at
        - next_anchor_at
        - pending_variant
        - created_at
        - metadata
        - test_line
        - shared
      description: >-
        A line. `billing_tier`, `byod`, `shared`, `test_line` and `inbound_only`
        tell the kinds of line apart: a rented line (two-way or inbound-only), a
        BYOD line, a shared line, a test line.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        An API key created in the iSnap dashboard, or a trial key, sent as
        `Authorization: Bearer <key>`. An API key starts with `isnap_live_` or
        `isnap_test_`; both act on the same account, lines and billing. A trial
        key acts on its trial only.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.