---
title: "Complete phone sign-in (verify code)"
method: POST
path: "/users/phone-sessions/verify"
tags: ["Public", "PhoneSessions"]
---

# Complete phone sign-in (verify code)

`POST /users/phone-sessions/verify`

## Request

- Base URL: `https://api.purplegrain.com/api/v1`
- URL: `https://api.purplegrain.com/api/v1/users/phone-sessions/verify`
- Auth: none declared

Passwordless phone sign-in, step 2: checks the SMS code. On success the
mobile is marked verified, the account is **created if new** (with an
unusable random password; `account_mode` applies then, default grower),
and a first-party Doorkeeper access token is returned — the same payload
as `POST /users/sign-in`.

With the optional `property_draft` (the landing page's map, design
handoff 29) and a number that has no account yet, the property — and the
business, when `owner_kind` is `business` — is created in the same
transaction as the account. An existing account signs in and the draft
is ignored. The draft is checked before the code for every number, so an
invalid one is a 422 that spends no code.

## Request body

- object
  - `mobile` string, required
  - `code` string, required: The 6-digit code from the SMS.
  - `account_mode` 'grower' | 'contractor': Applied only when the account is created by this verification; defaults to grower.
  - `property_draft` RegistrationPropertyDraft, nullable: The property a visitor mapped on the landing page before registering (design handoff 29). Created in the same transaction as the account — the business first when `owner_kind` is `business` (the new person its owner), then the property owned by the person or that business, named `name`, with `location.label` as its map label and `location.lng/lat` as its map point, then the ring saved exactly as `updateFarmBoundary` saves one (area measured server-side). An invalid draft fails the whole request with 422 and nothing is created; its errors point at `/data/attributes/property_draft.<field>`.
    - `name` string, required: Required.
    - `owner_kind` 'personal' | 'business': Defaults to personal.
    - `business_name` string, nullable: Required when `owner_kind` is business.
    - `location` SetupDraftLocation, nullable: The place the editor found for the property. `label` is required; `lng` and `lat` are both present or both absent. No other keys.
      - `label` string, required
      - `lng` number
      - `lat` number
    - `ring` array[], nullable: The corners, `[longitude, latitude]`, open or closed (first repeated last). Fewer than three distinct corners is not an error: the property is made without a boundary. Three or more must make a valid polygon (the boundary save's checks) enclosing less than 100,000 ha.
      - number[]
    - `area_ha` number, nullable: The client's own figure. Ignored; the area is measured from the ring.

## Response `200`

Signed in — Doorkeeper access token; includes `user_id`.

- DoorkeeperAccessTokenResponse: Access token issued by Doorkeeper. The same fields are returned from `POST /oauth/token` (RFC 6749). First-party endpoints (`POST /users/sign-in`, `POST /users/access-tokens`) add `user_id` for convenience.
  - `access_token` string, required: Opaque bearer token. Send as header Authorization: Bearer {token} on /api/v1/* routes.
  - `token_type` string, required
  - `expires_in` integer: Lifetime of the access token in seconds.
  - `refresh_token` string, nullable: Present when the client and grant type allow refresh tokens.
  - `scope` string: Granted scopes (space-separated).
  - `user_id` string, uuid, nullable: Only returned by first-party JSON endpoints (`/users/sign-in`, `/users/access-tokens`), not by `POST /oauth/token`.
  - `actor_id` string, uuid, nullable: The acting entity's id (first-party endpoints only). Equals `user_id` today; becomes the Organization id when a token is scoped to act for an organization.
  - `actor_type` 'User' | 'Organization', nullable: Polymorphic type of `actor_id` (first-party endpoints only).

## Other responses

- `403`: Forbidden — first-party only; refused to an API key or an assistant's token.
- `422`: Incorrect or expired code, or an invalid `property_draft` (errors point at `/data/attributes/property_draft.<field>`; nothing is created and no code is spent).

---

[API](https://skmtc.dev/purplegrain/apis/purple-grain-api.md) · [All operations](https://skmtc.dev/purplegrain/apis/purple-grain-api/llms.txt) · [OpenAPI document](https://skmtc.dev/purplegrain/apis/purple-grain-api/revisions/06540345bbbc?raw)
