Smart Capital Center API

Find a property by address, register it, upload its documents and order a valuation or a loan quote through the Smart Capital Center API. Every page works for two readers: the developer building the integration and the AI agent calling it.

Reading as
Base URL https://app.smartcapitalcenter.comVersion /api/v2Auth X-API-KEY header

If you're a person

Read top to bottom: the rules, pick a workflow, then open the operations it names. Every operation shows a copy-paste curl example.

If you're an agent

Switch to the Agent view at the top of this page for the plain-text version, use Copy as Markdown on any operation, or fetch the operation's own page with its Open page link (for example /api-docs/create-api-key). Load only the operations you need.

Rules for every call

These apply whether a person or an agent is making the request. Agents should treat them as hard constraints.

  1. Authenticate with X-API-KEY. Every /api/v2/public/* call takes the X-API-KEY header. Bearer tokens are only needed to create the first key; the API key calls accept either.
  2. Never expose secrets. Do not repeat API keys, access tokens, refresh tokens or passwords back to the user or into logs. Mask them (sq_****).
  3. Confirm before spending money. A FULL valuation charges $350. Name the property and the price and wait for an explicit yes. Never create or guess a cardToken.
  4. Confirm before destructive or account-level actions. That includes deleteApiKey and register.
  5. Refresh tokens are single use. Store the new pair immediately. Reusing an old refresh token signs the user out everywhere.
  6. Read the HTTP status code. Errors come back as real 4xx or 5xx codes with a message that explains why.
  7. Poll politely. Check an order with getOrder at most once a minute.
  8. Ask instead of choosing for the user when a search returns several parcels.

Which endpoint to call

Find the row that matches what you have, then call the operations in order.

  1. The user has a street address and wants a value or a loan quotesearchParcelscreatePropertycreateOrder
  2. The user has documents for the propertyuploadDocumentcreateOrder
  3. An order was placed and the user wants the resultgetOrder
  4. The user has a county id and parcel id (APN)createPropertycreateOrder
  5. There is no API key yetlogin or registercreateApiKey

Workflows

Value a property from an address

  1. searchParcels
  2. confirm the parcel with the user
  3. createProperty
  4. optional: uploadDocument for each document
  5. confirm order type and cost
  6. createOrder
  7. getOrder until COMPLETED or REJECTED

Set up access from nothing

  1. register or login
  2. createApiKey (Bearer token)
  3. use X-API-KEY from then on

Responses and errors

Every response uses the same wrapper. Failures return a real HTTP error code; read message for the reason.

{ "status": "success", "data": { }, "message": null, "code": null }
Code Meaning What to do
400 The request is invalid: a required field is missing, a format is wrong, or an enum value isn't allowed. Fix the request using message. Do not retry unchanged.
401 The API key is missing or invalid, the credentials are wrong, or a refresh token was reused. Check the header. For credential problems, tell the user. Never retry a refresh.
402 The card charge for a FULL valuation failed. Tell the user. Do not retry with the same card token unless they ask.
403 The API key belongs to another user. Stop and tell the user.
404 The property, parcel, request or API key does not exist, or the property or request belongs to another user. Check the id; look it up again if needed.
409 An account with this email already exists. Use login instead.
429 Too many sign-ups from this IP address. Wait before calling register again. Do not loop.
500 Something failed on SCC's side. Retry once after a short wait, then report the message and code to the user.

Get access

register

POST
/api/v2/auth/register
Copy as MarkdownOpen page

Creates a new evaluation account and returns an access token and refresh token right away. No confirmation email is sent, so the account works immediately.

Auth: None

Use when: The user has no SCC account and has asked you to create one for them.

Don't use when: The user already has an account (use login), or already has an API key (skip auth and call the API directly). Never register an account the user did not ask for.

Request body

Content type: application/json

Field Type Required Description
email string yes Account email. Example: agent@example.com.
password string yes Account password (plain — sent over TLS). Example: s3cret!.
firstName string no Optional first name. Example: Ada.
lastName string no Optional last name. Example: Lovelace.
phone string no Optional phone number. Example: +1 415 555 0100.

Notes for agents

  • Only email and password are required.
  • A 409 means the email is already registered. Switch to login and do not retry register.
  • The access token expires after 900 seconds (15 minutes). Use it right away to create an API key.
  • A 429 means too many sign-ups from this IP address. Wait before retrying; do not loop.

Example request

curl -X POST https://app.smartcapitalcenter.com/api/v2/auth/register \
  -H "Content-Type: application/json" \
  -d '{"email": "agent@example.com", "password": "s3cret!"}'

Response 200

Account created — tokens issued.

{
  "status": "success",
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...signature",
    "refresh_token": "def50200b8f1aA-9V0pQrSt...",
    "expires_in": 900,
    "token_type": "Bearer"
  },
  "message": null,
  "code": null
}

Errors

Code Meaning
400 Validation error — missing or malformed fields
409 A user with this email already exists
429 Too many registration attempts from this IP address; wait before retrying

Next: Call createApiKey with Authorization: Bearer <access_token>.

# register `POST /api/v2/auth/register` Creates a new evaluation account and returns an access token and refresh token right away. No confirmation email is sent, so the account works immediately. **Auth:** None **Use when:** The user has no SCC account and has asked you to create one for them. **Don't use when:** The user already has an account (use `login`), or already has an API key (skip auth and call the API directly). Never register an account the user did not ask for. ## Request body Content type: `application/json` | Field | Type | Required | Description | |---|---|---|---| | `email` | string | yes | Account email. Example: `agent@example.com`. | | `password` | string | yes | Account password (plain — sent over TLS). Example: `s3cret!`. | | `firstName` | string | no | Optional first name. Example: `Ada`. | | `lastName` | string | no | Optional last name. Example: `Lovelace`. | | `phone` | string | no | Optional phone number. Example: `+1 415 555 0100`. | ## Notes for agents - Only `email` and `password` are required. - A `409` means the email is already registered. Switch to `login` and do not retry `register`. - The access token expires after 900 seconds (15 minutes). Use it right away to create an API key. - A `429` means too many sign-ups from this IP address. Wait before retrying; do not loop. ## Example request ```bash curl -X POST https://app.smartcapitalcenter.com/api/v2/auth/register \ -H "Content-Type: application/json" \ -d '{"email": "agent@example.com", "password": "s3cret!"}' ``` ## Response `200` Account created — tokens issued. ```json { "status": "success", "data": { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...signature", "refresh_token": "def50200b8f1aA-9V0pQrSt...", "expires_in": 900, "token_type": "Bearer" }, "message": null, "code": null } ``` ## Errors | Code | Meaning | |---|---| | 400 | Validation error — missing or malformed fields | | 409 | A user with this email already exists | | 429 | Too many registration attempts from this IP address; wait before retrying | **Next:** Call `createApiKey` with `Authorization: Bearer <access_token>`.

login

POST
/api/v2/auth/login
Copy as MarkdownOpen page

Exchanges an email and password for a short-lived access token and a long-lived refresh token.

Auth: None

Use when: The user has an account and you need a bearer token, usually to create an API key.

Don't use when: You already have a working API key. Every data endpoint accepts the X-API-KEY header, so no login is needed.

Request body

Content type: application/json

Field Type Required Description
email string yes Account email. Example: user@example.com.
password string yes Account password (plain — sent over TLS). Example: s3cret!.

Notes for agents

  • A 401 can mean wrong credentials, a disabled account, an IP address that isn't allowed, or an account that must sign in through SSO. Report the message to the user; do not loop on retries.
  • Never store or repeat the password after this call.
  • The valuation calls need an account with API access. Accounts created with register have it. An existing account can still create a key, but if its valuation calls are refused, tell the user their account does not have API access.

Example request

curl -X POST https://app.smartcapitalcenter.com/api/v2/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "user@example.com", "password": "s3cret!"}'

Response 200

Authentication successful — tokens issued.

{
  "status": "success",
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...signature",
    "refresh_token": "def50200b8f1aA-9V0pQrSt...",
    "expires_in": 900,
    "token_type": "Bearer"
  },
  "message": null,
  "code": null
}

Errors

Code Meaning
400 Validation error — missing or malformed fields
401 Invalid credentials, disabled account, IP not allowed, or SSO-only login required

Next: Call createApiKey, or use the bearer token wherever it is accepted.

# login `POST /api/v2/auth/login` Exchanges an email and password for a short-lived access token and a long-lived refresh token. **Auth:** None **Use when:** The user has an account and you need a bearer token, usually to create an API key. **Don't use when:** You already have a working API key. Every data endpoint accepts the `X-API-KEY` header, so no login is needed. ## Request body Content type: `application/json` | Field | Type | Required | Description | |---|---|---|---| | `email` | string | yes | Account email. Example: `user@example.com`. | | `password` | string | yes | Account password (plain — sent over TLS). Example: `s3cret!`. | ## Notes for agents - A `401` can mean wrong credentials, a disabled account, an IP address that isn't allowed, or an account that must sign in through SSO. Report the `message` to the user; do not loop on retries. - Never store or repeat the password after this call. - The valuation calls need an account with API access. Accounts created with `register` have it. An existing account can still create a key, but if its valuation calls are refused, tell the user their account does not have API access. ## Example request ```bash curl -X POST https://app.smartcapitalcenter.com/api/v2/auth/login \ -H "Content-Type: application/json" \ -d '{"email": "user@example.com", "password": "s3cret!"}' ``` ## Response `200` Authentication successful — tokens issued. ```json { "status": "success", "data": { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...signature", "refresh_token": "def50200b8f1aA-9V0pQrSt...", "expires_in": 900, "token_type": "Bearer" }, "message": null, "code": null } ``` ## Errors | Code | Meaning | |---|---| | 400 | Validation error — missing or malformed fields | | 401 | Invalid credentials, disabled account, IP not allowed, or SSO-only login required | **Next:** Call `createApiKey`, or use the bearer token wherever it is accepted.

refresh

POST
/api/v2/auth/refresh
Copy as MarkdownOpen page

Trades a refresh token for a new access token and a new refresh token. The old refresh token stops working immediately.

Auth: None

Use when: The access token has expired (after 900 seconds) and you still need bearer auth.

Don't use when: You are using an API key. API keys do not use refresh tokens.

Request body

Content type: application/json

Field Type Required Description
refresh_token string yes Opaque refresh token previously issued by /auth/login or /auth/refresh. Example: def50200b8f1aA-9V0p...rotated.

Notes for agents

  • Refresh tokens are single use. Save the new refresh_token before doing anything else.
  • Sending a refresh token that was already used is treated as a stolen token: every active session for that user is revoked and the call fails with 401. Never retry a refresh with a token you have already sent.

Example request

curl -X POST https://app.smartcapitalcenter.com/api/v2/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{"refresh_token": "def50200..."}'

Response 200

Rotation successful — new token pair issued. The old refresh token is now invalid.

{
  "status": "success",
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...newsig",
    "refresh_token": "def50200ROTATED...",
    "expires_in": 900,
    "token_type": "Bearer"
  },
  "message": null,
  "code": null
}

Errors

Code Meaning
400 Validation error — missing refresh_token
401 Unknown / expired / already-revoked refresh token. If the token was already revoked, all active refresh tokens for the user are additionally revoked (reuse detection).

Next: Replace both stored tokens with the new pair.

# refresh `POST /api/v2/auth/refresh` Trades a refresh token for a new access token and a new refresh token. The old refresh token stops working immediately. **Auth:** None **Use when:** The access token has expired (after 900 seconds) and you still need bearer auth. **Don't use when:** You are using an API key. API keys do not use refresh tokens. ## Request body Content type: `application/json` | Field | Type | Required | Description | |---|---|---|---| | `refresh_token` | string | yes | Opaque refresh token previously issued by /auth/login or /auth/refresh. Example: `def50200b8f1aA-9V0p...rotated`. | ## Notes for agents - Refresh tokens are single use. Save the new `refresh_token` before doing anything else. - Sending a refresh token that was already used is treated as a stolen token: every active session for that user is revoked and the call fails with `401`. Never retry a refresh with a token you have already sent. ## Example request ```bash curl -X POST https://app.smartcapitalcenter.com/api/v2/auth/refresh \ -H "Content-Type: application/json" \ -d '{"refresh_token": "def50200..."}' ``` ## Response `200` Rotation successful — new token pair issued. The old refresh token is now invalid. ```json { "status": "success", "data": { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...newsig", "refresh_token": "def50200ROTATED...", "expires_in": 900, "token_type": "Bearer" }, "message": null, "code": null } ``` ## Errors | Code | Meaning | |---|---| | 400 | Validation error — missing refresh_token | | 401 | Unknown / expired / already-revoked refresh token. If the token was already revoked, all active refresh tokens for the user are additionally revoked (reuse detection). | **Next:** Replace both stored tokens with the new pair.

createApiKey

POST
/api/v2/public/api-keys
Copy as MarkdownOpen page

Creates a named API key for the signed-in user. The key goes in the X-API-KEY header on every other call.

Auth: Authorization: Bearer <access_token> (or X-API-KEY)

Use when: Right after register or login, or when the user wants a separate key for a new integration.

Don't use when: A working key already exists for this integration. Check with getUserApiKeys first.

Request body

Content type: application/json

Field Type Required Description
name string yes Name of the API key. Max 100 chars. Example: My Application API Key.
description string no Description of the API key's purpose. Max 500 chars. Example: Used by the valuation integration.
expiresInDays integer no Number of days until the API key expires (null for no expiration). Example: 365.

Notes for agents

  • Send the bearer token from register or login in the Authorization header.
  • Omit expiresInDays for a key that never expires. Prefer an expiry when the user hasn't said otherwise, and tell them what you chose.
  • data.keyValue is returned only once. Show it to the user once, then mask it (sq_****) in anything you write afterwards.

Example request

curl -X POST https://app.smartcapitalcenter.com/api/v2/public/api-keys \
  -H "Authorization: Bearer $SCC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Valuation integration", "description": "Used by our valuation workflow", "expiresInDays": 365}'

Response 200

API key created successfully.

Standard envelope with data containing:

Field Type Description
id integer Unique identifier of the API key.
keyValue string The API key to send in the X-API-KEY header. Shown only in this response. Example: sq_1a2b3c4d5e6f7g8h9i0j.
name string Name of the API key.
description string Description of the API key's purpose.
createdAt string When the API key was created.
expiresAt string When the API key expires (null if no expiration).
isActive boolean Whether the API key is active.

Errors

Code Meaning
400 Invalid request
401 Missing or invalid credentials

Next: Use X-API-KEY: <key> on all /api/v2/public/* calls.

# createApiKey `POST /api/v2/public/api-keys` Creates a named API key for the signed-in user. The key goes in the `X-API-KEY` header on every other call. **Auth:** `Authorization: Bearer <access_token>` (or `X-API-KEY`) **Use when:** Right after `register` or `login`, or when the user wants a separate key for a new integration. **Don't use when:** A working key already exists for this integration. Check with `getUserApiKeys` first. ## Request body Content type: `application/json` | Field | Type | Required | Description | |---|---|---|---| | `name` | string | yes | Name of the API key. Max 100 chars. Example: `My Application API Key`. | | `description` | string | no | Description of the API key's purpose. Max 500 chars. Example: `Used by the valuation integration`. | | `expiresInDays` | integer | no | Number of days until the API key expires (null for no expiration). Example: `365`. | ## Notes for agents - Send the bearer token from `register` or `login` in the `Authorization` header. - Omit `expiresInDays` for a key that never expires. Prefer an expiry when the user hasn't said otherwise, and tell them what you chose. - `data.keyValue` is returned only once. Show it to the user once, then mask it (`sq_****`) in anything you write afterwards. ## Example request ```bash curl -X POST https://app.smartcapitalcenter.com/api/v2/public/api-keys \ -H "Authorization: Bearer $SCC_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name": "Valuation integration", "description": "Used by our valuation workflow", "expiresInDays": 365}' ``` ## Response `200` API key created successfully. Standard envelope with `data` containing: | Field | Type | Description | |---|---|---| | `id` | integer | Unique identifier of the API key. | | `keyValue` | string | The API key to send in the `X-API-KEY` header. Shown only in this response. Example: `sq_1a2b3c4d5e6f7g8h9i0j`. | | `name` | string | Name of the API key. | | `description` | string | Description of the API key's purpose. | | `createdAt` | string | When the API key was created. | | `expiresAt` | string | When the API key expires (null if no expiration). | | `isActive` | boolean | Whether the API key is active. | ## Errors | Code | Meaning | |---|---| | 400 | Invalid request | | 401 | Missing or invalid credentials | **Next:** Use `X-API-KEY: <key>` on all `/api/v2/public/*` calls.

getUserApiKeys

GET
/api/v2/public/api-keys
Copy as MarkdownOpen page

Lists the active API keys for the authenticated user.

Auth: X-API-KEY: <your key> header (or Authorization: Bearer <access_token>)

Use when: Before creating a key, or when the user asks which keys exist.

Notes for agents

  • Never print full key values back to the user.

Example request

curl https://app.smartcapitalcenter.com/api/v2/public/api-keys \
  -H "X-API-KEY: $SCC_API_KEY"

Response 200

List of API keys retrieved successfully. Key values are masked.

Standard envelope with data as a list of:

Field Type Description
id integer Unique identifier of the API key.
maskedKeyValue string Masked key for display. Example: sq_1...j0k9.
name string Name of the API key.
description string Description of the API key's purpose.
createdAt string When the API key was created.
expiresAt string When the API key expires (null if no expiration).
lastUsedAt string When the API key was last used.
isActive boolean Whether the API key is active.

Next: deleteApiKey to revoke one, or createApiKey if none fits.

# getUserApiKeys `GET /api/v2/public/api-keys` Lists the active API keys for the authenticated user. **Auth:** `X-API-KEY: <your key>` header (or `Authorization: Bearer <access_token>`) **Use when:** Before creating a key, or when the user asks which keys exist. ## Notes for agents - Never print full key values back to the user. ## Example request ```bash curl https://app.smartcapitalcenter.com/api/v2/public/api-keys \ -H "X-API-KEY: $SCC_API_KEY" ``` ## Response `200` List of API keys retrieved successfully. Key values are masked. Standard envelope with `data` as a list of: | Field | Type | Description | |---|---|---| | `id` | integer | Unique identifier of the API key. | | `maskedKeyValue` | string | Masked key for display. Example: `sq_1...j0k9`. | | `name` | string | Name of the API key. | | `description` | string | Description of the API key's purpose. | | `createdAt` | string | When the API key was created. | | `expiresAt` | string | When the API key expires (null if no expiration). | | `lastUsedAt` | string | When the API key was last used. | | `isActive` | boolean | Whether the API key is active. | **Next:** `deleteApiKey` to revoke one, or `createApiKey` if none fits.

deleteApiKey

DELETE
/api/v2/public/api-keys/{id}
Copy as MarkdownOpen page

Deactivates one of the user's API keys. Anything using that key stops working.

Auth: X-API-KEY: <your key> header (or Authorization: Bearer <access_token>)

Use when: The user explicitly asks to revoke a key, or a key has leaked.

Don't use when: Cleaning up on your own initiative. Always confirm with the user first, naming the key.

Parameters

Name In Type Required Description
id path integer yes ID of the API key to delete.

Notes for agents

  • 403 means the key belongs to another user. 404 means the id does not exist.
  • Do not delete the key you are currently authenticating with unless the user understands the session will stop working.

Example request

curl -X DELETE https://app.smartcapitalcenter.com/api/v2/public/api-keys/42 \
  -H "X-API-KEY: $SCC_API_KEY"

Response 200

API key deleted successfully.

Standard envelope: {"status", "data", "message", "code"}.

Errors

Code Meaning
403 Access denied - API key belongs to another user
404 API key not found
# deleteApiKey `DELETE /api/v2/public/api-keys/{id}` Deactivates one of the user's API keys. Anything using that key stops working. **Auth:** `X-API-KEY: <your key>` header (or `Authorization: Bearer <access_token>`) **Use when:** The user explicitly asks to revoke a key, or a key has leaked. **Don't use when:** Cleaning up on your own initiative. Always confirm with the user first, naming the key. ## Parameters | Name | In | Type | Required | Description | |---|---|---|---|---| | `id` | path | integer | yes | ID of the API key to delete. | ## Notes for agents - `403` means the key belongs to another user. `404` means the id does not exist. - Do not delete the key you are currently authenticating with unless the user understands the session will stop working. ## Example request ```bash curl -X DELETE https://app.smartcapitalcenter.com/api/v2/public/api-keys/42 \ -H "X-API-KEY: $SCC_API_KEY" ``` ## Response `200` API key deleted successfully. Standard envelope: `{"status", "data", "message", "code"}`. ## Errors | Code | Meaning | |---|---| | 403 | Access denied - API key belongs to another user | | 404 | API key not found |

Value a property

searchParcels

GET
/api/v2/public/valuation/parcels
Copy as MarkdownOpen page

Looks up a street address and returns the land parcels at that location. Each parcel has the countyId and parcelId needed to create a property.

Auth: X-API-KEY: <your key> header

Use when: The user gives you an address and wants a valuation or loan quote.

Don't use when: You already have the county id and parcel id (APN). Go straight to createProperty.

Parameters

Name In Type Required Description
address query string yes Full street address, including city, state and ZIP when known.

Notes for agents

  • matchedAddress is the address the geocoder actually matched. If it differs meaningfully from what the user typed, confirm before continuing.
  • One address can return several parcels. If there is more than one, show the user the options (property type, units, size) and let them choose. Do not pick silently.
  • A 404 or an empty parcels array means no parcel was found at the matched address, and a 400 means the address could not be geocoded. In each case ask the user for a more complete address or the APN.

Example request

curl -G https://app.smartcapitalcenter.com/api/v2/public/valuation/parcels \
  -H "X-API-KEY: $SCC_API_KEY" \
  --data-urlencode "address=123 Main St, Los Angeles, CA 90012"

Response 200

OK.

Standard envelope with data containing:

Field Type Description
matchedAddress string The address Google matched for the query.
parcels array Candidate parcels at the matched address.
parcels[].countyId string County id (5-digit FIPS code) — pass to create-property. Example: 06037.
parcels[].parcelId string Parcel id (APN) — pass to create-property. Example: 5555-012-034.
parcels[].propertyType string Property type.
parcels[].units integer Number of units, if known.
parcels[].size integer Building size in sqft, if known.

Errors

Code Meaning
400 Address could not be geocoded
404 No parcels at the matched address

Next: createProperty with the chosen parcel's countyId and parcelId.

# searchParcels `GET /api/v2/public/valuation/parcels` Looks up a street address and returns the land parcels at that location. Each parcel has the `countyId` and `parcelId` needed to create a property. **Auth:** `X-API-KEY: <your key>` header **Use when:** The user gives you an address and wants a valuation or loan quote. **Don't use when:** You already have the county id and parcel id (APN). Go straight to `createProperty`. ## Parameters | Name | In | Type | Required | Description | |---|---|---|---|---| | `address` | query | string | yes | Full street address, including city, state and ZIP when known. | ## Notes for agents - `matchedAddress` is the address the geocoder actually matched. If it differs meaningfully from what the user typed, confirm before continuing. - One address can return several parcels. If there is more than one, show the user the options (property type, units, size) and let them choose. Do not pick silently. - A `404` or an empty `parcels` array means no parcel was found at the matched address, and a `400` means the address could not be geocoded. In each case ask the user for a more complete address or the APN. ## Example request ```bash curl -G https://app.smartcapitalcenter.com/api/v2/public/valuation/parcels \ -H "X-API-KEY: $SCC_API_KEY" \ --data-urlencode "address=123 Main St, Los Angeles, CA 90012" ``` ## Response `200` OK. Standard envelope with `data` containing: | Field | Type | Description | |---|---|---| | `matchedAddress` | string | The address Google matched for the query. | | `parcels` | array | Candidate parcels at the matched address. | | `parcels[].countyId` | string | County id (5-digit FIPS code) — pass to create-property. Example: `06037`. | | `parcels[].parcelId` | string | Parcel id (APN) — pass to create-property. Example: `5555-012-034`. | | `parcels[].propertyType` | string | Property type. | | `parcels[].units` | integer | Number of units, if known. | | `parcels[].size` | integer | Building size in sqft, if known. | ## Errors | Code | Meaning | |---|---| | 400 | Address could not be geocoded | | 404 | No parcels at the matched address | **Next:** `createProperty` with the chosen parcel's `countyId` and `parcelId`.

createProperty

POST
/api/v2/public/valuation/property
Copy as MarkdownOpen page

Registers a parcel as a property in the user's account and returns its numeric propertyId.

Auth: X-API-KEY: <your key> header

Use when: After searchParcels, or whenever you have a county id and parcel id.

Request body

Content type: application/json

Field Type Required Description
countyId string yes County id of the parcel (5-digit FIPS code). Example: 06037.
parcelId string yes Parcel id (APN) within the county. Example: 5555-012-034.
propertyName string no Optional display name for the property. Example: 123 Main St.

Notes for agents

  • Idempotent: if the property already exists, the existing one comes back unchanged. It is safe to retry.
  • Keep the returned propertyId. Uploads and orders need it.

Example request

curl -X POST https://app.smartcapitalcenter.com/api/v2/public/valuation/property \
  -H "X-API-KEY: $SCC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"countyId": "06037", "parcelId": "5555-012-034", "propertyName": "123 Main St"}'

Response 200

OK.

Standard envelope with data containing:

Field Type Description
propertyId integer Numeric property id — use this for uploads and valuation requests. Example: 123456.
countyId string County id of the underlying parcel.
parcelId string Parcel id (APN) of the underlying parcel.
propertyName string The propertyName sent in this request, echoed back. An existing property keeps its stored name.

Errors

Code Meaning
400 Validation error
404 Parcel not found

Next: uploadDocument if the user has documents for the property, otherwise createOrder.

# createProperty `POST /api/v2/public/valuation/property` Registers a parcel as a property in the user's account and returns its numeric `propertyId`. **Auth:** `X-API-KEY: <your key>` header **Use when:** After `searchParcels`, or whenever you have a county id and parcel id. ## Request body Content type: `application/json` | Field | Type | Required | Description | |---|---|---|---| | `countyId` | string | yes | County id of the parcel (5-digit FIPS code). Example: `06037`. | | `parcelId` | string | yes | Parcel id (APN) within the county. Example: `5555-012-034`. | | `propertyName` | string | no | Optional display name for the property. Example: `123 Main St`. | ## Notes for agents - Idempotent: if the property already exists, the existing one comes back unchanged. It is safe to retry. - Keep the returned `propertyId`. Uploads and orders need it. ## Example request ```bash curl -X POST https://app.smartcapitalcenter.com/api/v2/public/valuation/property \ -H "X-API-KEY: $SCC_API_KEY" \ -H "Content-Type: application/json" \ -d '{"countyId": "06037", "parcelId": "5555-012-034", "propertyName": "123 Main St"}' ``` ## Response `200` OK. Standard envelope with `data` containing: | Field | Type | Description | |---|---|---| | `propertyId` | integer | Numeric property id — use this for uploads and valuation requests. Example: `123456`. | | `countyId` | string | County id of the underlying parcel. | | `parcelId` | string | Parcel id (APN) of the underlying parcel. | | `propertyName` | string | The `propertyName` sent in this request, echoed back. An existing property keeps its stored name. | ## Errors | Code | Meaning | |---|---| | 400 | Validation error | | 404 | Parcel not found | **Next:** `uploadDocument` if the user has documents for the property, otherwise `createOrder`.

uploadDocument

POST
/api/v2/public/valuation/upload-to-property/{propertyId}
Copy as MarkdownOpen page

Uploads a document, such as a rent roll or operating statement, and attaches it to a property. Use the returned document id in createOrder.

Auth: X-API-KEY: <your key> header

Use when: The user has documents for the property (rent roll, operating statement, appraisal) and wants them used in the valuation or loan quote.

Don't use when: The property does not exist yet (call createProperty first), or the user has not given you a file.

Parameters

Name In Type Required Description
propertyId path integer yes Numeric SCC property id (from createProperty). Example: 123456.
propertyBuildingId query integer no Property building identifier (optional).

Request body

Content type: multipart/form-data

Field Type Required Description
file binary yes The document. Allowed types: pdf, jpg, jpeg, png, gif, xls, xlsx, xlsm, xlsb, csv, docx, doc. Maximum 100 MB.
name string yes Document name. Letters, digits, spaces and . , _ ( ) - [ ] + & # ', up to 255 characters. Example: Rent Roll (Wellington Center).
type string no Document type; drives the extraction. Use OTHER when unsure. See document types. Example: RENT_ROLL.
date integer no Document date as Unix time in milliseconds. Example: 1707215736000.
pages string no Page range to process (PDF). Example: 1-5.
sheetNumber integer no Sheet number to process (Excel), 1-based. Example: 1.
parseType string no Parsing engine for the first pass over a rent roll or operating statement: PDFBOX (PDF text layer), OCR or OCR2 (OCR engines), GENERATIVE_AI (LLM extraction). Omit to use the default.

Notes for agents

  • Only upload files the user gave you, and name them clearly.
  • The file is stored right away; data extraction continues in the background.
  • Keep the returned data.id and pass it in createOrder documentIds for the same property.
  • Set type when you know it, so the right extraction runs. Use OTHER when unsure.
  • Every field except file may also be sent as a query parameter.
  • A 404 means the property does not exist or belongs to another user.

Example request

curl -X POST https://app.smartcapitalcenter.com/api/v2/public/valuation/upload-to-property/123456 \
  -H "X-API-KEY: $SCC_API_KEY" \
  -F "file=@rent-roll.pdf" \
  -F "name=Rent Roll (123 Main St)" \
  -F "type=RENT_ROLL"

Response 202

Document stored and attached to the property; data is the document.

Standard envelope with data containing:

Field Type Description
id integer Document id; pass it in createOrder documentIds.
name string Document name.
type string Document type.
fileName string Uploaded file name.
statusLabel string Human-readable document status.

Errors

Code Meaning
400 Invalid input (missing fields, wrong formats, unsupported file type)
401 Missing or invalid API key
404 Property not found or not owned by the caller
500 Internal server error during upload

Next: createOrder with the returned data.id in documentIds.

# uploadDocument `POST /api/v2/public/valuation/upload-to-property/{propertyId}` Uploads a document, such as a rent roll or operating statement, and attaches it to a property. Use the returned document id in `createOrder`. **Auth:** `X-API-KEY: <your key>` header **Use when:** The user has documents for the property (rent roll, operating statement, appraisal) and wants them used in the valuation or loan quote. **Don't use when:** The property does not exist yet (call `createProperty` first), or the user has not given you a file. ## Parameters | Name | In | Type | Required | Description | |---|---|---|---|---| | `propertyId` | path | integer | yes | Numeric SCC property id (from `createProperty`). Example: `123456`. | | `propertyBuildingId` | query | integer | no | Property building identifier (optional). | ## Request body Content type: `multipart/form-data` | Field | Type | Required | Description | |---|---|---|---| | `file` | binary | yes | The document. Allowed types: pdf, jpg, jpeg, png, gif, xls, xlsx, xlsm, xlsb, csv, docx, doc. Maximum 100 MB. | | `name` | string | yes | Document name. Letters, digits, spaces and `. , _ ( ) - [ ] + & # '`, up to 255 characters. Example: `Rent Roll (Wellington Center)`. | | `type` | string | no | Document type; drives the extraction. Use `OTHER` when unsure. See document types. Example: `RENT_ROLL`. | | `date` | integer | no | Document date as Unix time in milliseconds. Example: `1707215736000`. | | `pages` | string | no | Page range to process (PDF). Example: `1-5`. | | `sheetNumber` | integer | no | Sheet number to process (Excel), 1-based. Example: `1`. | | `parseType` | string | no | Parsing engine for the first pass over a rent roll or operating statement: `PDFBOX` (PDF text layer), `OCR` or `OCR2` (OCR engines), `GENERATIVE_AI` (LLM extraction). Omit to use the default. | ## Notes for agents - Only upload files the user gave you, and name them clearly. - The file is stored right away; data extraction continues in the background. - Keep the returned `data.id` and pass it in `createOrder` `documentIds` for the same property. - Set `type` when you know it, so the right extraction runs. Use `OTHER` when unsure. - Every field except `file` may also be sent as a query parameter. - A `404` means the property does not exist or belongs to another user. ## Example request ```bash curl -X POST https://app.smartcapitalcenter.com/api/v2/public/valuation/upload-to-property/123456 \ -H "X-API-KEY: $SCC_API_KEY" \ -F "file=@rent-roll.pdf" \ -F "name=Rent Roll (123 Main St)" \ -F "type=RENT_ROLL" ``` ## Response `202` Document stored and attached to the property; `data` is the document. Standard envelope with `data` containing: | Field | Type | Description | |---|---|---| | `id` | integer | Document id; pass it in `createOrder` `documentIds`. | | `name` | string | Document name. | | `type` | string | Document type. | | `fileName` | string | Uploaded file name. | | `statusLabel` | string | Human-readable document status. | ## Errors | Code | Meaning | |---|---| | 400 | Invalid input (missing fields, wrong formats, unsupported file type) | | 401 | Missing or invalid API key | | 404 | Property not found or not owned by the caller | | 500 | Internal server error during upload | **Next:** `createOrder` with the returned `data.id` in `documentIds`.

createOrder

POST
/api/v2/public/valuation/order
Copy as MarkdownOpen page

Requests a full valuation (FULL) or a loan quote (LOAN) for a property the user owns.

Auth: X-API-KEY: <your key> header

Use when: The property exists and the user has asked for a valuation or a loan quote.

Don't use when: Placing a FULL order without explicit, specific approval from the user.

Request body

Content type: application/json

Field Type Required Description
propertyId integer yes Numeric id of the property (from the create-property step). Example: 123456.
orderType string yes Order type: FULL (detailed valuation) or LOAN (loan quote). Example: FULL.
documentIds array of integer no Optional ids of documents uploaded to this property with uploadDocument (its data.id).
cardToken string no Stripe card token (tok_.../pm_...) created client-side. Required for a FULL valuation ($350 charge); ignored for LOAN quotes. Example: tok_visa.

Notes for agents

  • FULL costs $350 and charges a card. Before calling, tell the user the property, the order type and the $350 charge, and wait for a clear yes.
  • LOAN quotes are free. cardToken is ignored for them.
  • cardToken must be a Stripe token (tok_... or pm_...) created in the user's browser or app. Never invent one, and never ask the user to paste raw card numbers to you.
  • documentIds come from uploadDocument on this same property.
  • The response data.id is the request id. Check progress with getOrder, at most once a minute, until status is COMPLETED or REJECTED.
  • A 402 means the card charge failed. Tell the user; do not retry with the same card token unless they ask.

Example request

curl -X POST https://app.smartcapitalcenter.com/api/v2/public/valuation/order \
  -H "X-API-KEY: $SCC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"propertyId": 123456, "orderType": "LOAN", "documentIds": [9876]}'

Response 200

OK.

Standard envelope with data containing:

Field Type Description
id integer Request id; use it with getOrder.
propertyId integer Numeric property id the request belongs to.
loanDetailsId integer —
propertyType string —
propertyName string —
address string —
countyId string —
parcelId string —
documents array —
documents[].id integer —
documents[].type string Enum, see document types.
documents[].name string —
documents[].fileName string —
documents[].documentStatus string —
documents[].documentStatusLabel string —
documents[].rrId integer —
documents[].osId integer —
documents[].documentDate string —
requesterId integer —
requesterEmail string —
servicerId integer —
servicerEmail string —
type string Request type: VALUATION (detailed valuation, orderType FULL) or LOAN (loan quote).
typeLabel string Human-readable request type.
status string Processing status: REQUEST_STARTED, REQUEST_SUBMITTED, REQUEST_APPROVED, WAITING_STANDARDIZATION, STANDARDIZED_NOT_REVIEWED, IN_PROGRESS_BY_SC, IN_PROGRESS_BY_USER, REQUEST_INFO, COMPLETED or REJECTED. COMPLETED and REJECTED are final.
statusLabel string Human-readable status.
createdAtTimestamp string —
updatedAtTimestamp string —
completedAtTimestamp string Set once the request is COMPLETED.
message string Message from the analyst, if any.
emailNotificationSentAt integer —

Errors

Code Meaning
400 Validation error, or cardToken missing for a FULL valuation
402 Card charge failed
404 Property not found or not owned by the caller

Next: getOrder with the returned data.id.

# createOrder `POST /api/v2/public/valuation/order` Requests a full valuation (`FULL`) or a loan quote (`LOAN`) for a property the user owns. **Auth:** `X-API-KEY: <your key>` header **Use when:** The property exists and the user has asked for a valuation or a loan quote. **Don't use when:** Placing a `FULL` order without explicit, specific approval from the user. ## Request body Content type: `application/json` | Field | Type | Required | Description | |---|---|---|---| | `propertyId` | integer | yes | Numeric id of the property (from the create-property step). Example: `123456`. | | `orderType` | string | yes | Order type: FULL (detailed valuation) or LOAN (loan quote). Example: `FULL`. | | `documentIds` | array of integer | no | Optional ids of documents uploaded to this property with `uploadDocument` (its `data.id`). | | `cardToken` | string | no | Stripe card token (tok_.../pm_...) created client-side. Required for a FULL valuation ($350 charge); ignored for LOAN quotes. Example: `tok_visa`. | ## Notes for agents - **`FULL` costs $350 and charges a card.** Before calling, tell the user the property, the order type and the $350 charge, and wait for a clear yes. - `LOAN` quotes are free. `cardToken` is ignored for them. - `cardToken` must be a Stripe token (`tok_...` or `pm_...`) created in the user's browser or app. Never invent one, and never ask the user to paste raw card numbers to you. - `documentIds` come from `uploadDocument` on this same property. - The response `data.id` is the request id. Check progress with `getOrder`, at most once a minute, until `status` is `COMPLETED` or `REJECTED`. - A `402` means the card charge failed. Tell the user; do not retry with the same card token unless they ask. ## Example request ```bash curl -X POST https://app.smartcapitalcenter.com/api/v2/public/valuation/order \ -H "X-API-KEY: $SCC_API_KEY" \ -H "Content-Type: application/json" \ -d '{"propertyId": 123456, "orderType": "LOAN", "documentIds": [9876]}' ``` ## Response `200` OK. Standard envelope with `data` containing: | Field | Type | Description | |---|---|---| | `id` | integer | Request id; use it with `getOrder`. | | `propertyId` | integer | Numeric property id the request belongs to. | | `loanDetailsId` | integer | — | | `propertyType` | string | — | | `propertyName` | string | — | | `address` | string | — | | `countyId` | string | — | | `parcelId` | string | — | | `documents` | array | — | | `documents[].id` | integer | — | | `documents[].type` | string | Enum, see document types. | | `documents[].name` | string | — | | `documents[].fileName` | string | — | | `documents[].documentStatus` | string | — | | `documents[].documentStatusLabel` | string | — | | `documents[].rrId` | integer | — | | `documents[].osId` | integer | — | | `documents[].documentDate` | string | — | | `requesterId` | integer | — | | `requesterEmail` | string | — | | `servicerId` | integer | — | | `servicerEmail` | string | — | | `type` | string | Request type: `VALUATION` (detailed valuation, orderType FULL) or `LOAN` (loan quote). | | `typeLabel` | string | Human-readable request type. | | `status` | string | Processing status: `REQUEST_STARTED`, `REQUEST_SUBMITTED`, `REQUEST_APPROVED`, `WAITING_STANDARDIZATION`, `STANDARDIZED_NOT_REVIEWED`, `IN_PROGRESS_BY_SC`, `IN_PROGRESS_BY_USER`, `REQUEST_INFO`, `COMPLETED` or `REJECTED`. `COMPLETED` and `REJECTED` are final. | | `statusLabel` | string | Human-readable status. | | `createdAtTimestamp` | string | — | | `updatedAtTimestamp` | string | — | | `completedAtTimestamp` | string | Set once the request is `COMPLETED`. | | `message` | string | Message from the analyst, if any. | | `emailNotificationSentAt` | integer | — | ## Errors | Code | Meaning | |---|---| | 400 | Validation error, or `cardToken` missing for a `FULL` valuation | | 402 | Card charge failed | | 404 | Property not found or not owned by the caller | **Next:** `getOrder` with the returned `data.id`.

getOrder

GET
/api/v2/public/valuation/order/{id}
Copy as MarkdownOpen page

Returns a valuation or loan-quote request created by createOrder, with its current status. Only the user who placed the order can read it.

Auth: X-API-KEY: <your key> header

Use when: After createOrder, to check whether the valuation or loan quote is ready.

Don't use when: Checking more than once a minute.

Parameters

Name In Type Required Description
id path integer yes Request id (data.id from createOrder).

Notes for agents

  • Check at most once a minute.
  • Stop when status is COMPLETED or REJECTED; both are final. Report statusLabel and any message to the user.
  • Only the user who placed the order can read it. A 404 means the request does not exist or belongs to another user.

Example request

curl https://app.smartcapitalcenter.com/api/v2/public/valuation/order/98765 \
  -H "X-API-KEY: $SCC_API_KEY"

Response 200

Request found; data is the request.

Standard envelope with data in the same shape as the createOrder response. The fields you need most:

Field Type Description
id integer Request id.
propertyId integer Numeric property id the request belongs to.
type string Request type: VALUATION (detailed valuation, orderType FULL) or LOAN (loan quote). The schema also lists SPREADING, which this API never creates.
typeLabel string Human-readable request type.
status string Processing status. COMPLETED and REJECTED are final; see createOrder for every value.
statusLabel string Human-readable status.
documents array Documents attached to the request.
createdAtTimestamp string When the request was created.
updatedAtTimestamp string When the request last changed.
completedAtTimestamp string Set once the request is COMPLETED.
message string Message from the analyst, if any.

Errors

Code Meaning
404 Request not found or not owned by the caller
# getOrder `GET /api/v2/public/valuation/order/{id}` Returns a valuation or loan-quote request created by `createOrder`, with its current status. Only the user who placed the order can read it. **Auth:** `X-API-KEY: <your key>` header **Use when:** After `createOrder`, to check whether the valuation or loan quote is ready. **Don't use when:** Checking more than once a minute. ## Parameters | Name | In | Type | Required | Description | |---|---|---|---|---| | `id` | path | integer | yes | Request id (`data.id` from `createOrder`). | ## Notes for agents - Check at most once a minute. - Stop when `status` is `COMPLETED` or `REJECTED`; both are final. Report `statusLabel` and any `message` to the user. - Only the user who placed the order can read it. A `404` means the request does not exist or belongs to another user. ## Example request ```bash curl https://app.smartcapitalcenter.com/api/v2/public/valuation/order/98765 \ -H "X-API-KEY: $SCC_API_KEY" ``` ## Response `200` Request found; `data` is the request. Standard envelope with `data` in the same shape as the `createOrder` response. The fields you need most: | Field | Type | Description | |---|---|---| | `id` | integer | Request id. | | `propertyId` | integer | Numeric property id the request belongs to. | | `type` | string | Request type: `VALUATION` (detailed valuation, orderType FULL) or `LOAN` (loan quote). The schema also lists `SPREADING`, which this API never creates. | | `typeLabel` | string | Human-readable request type. | | `status` | string | Processing status. `COMPLETED` and `REJECTED` are final; see `createOrder` for every value. | | `statusLabel` | string | Human-readable status. | | `documents` | array | Documents attached to the request. | | `createdAtTimestamp` | string | When the request was created. | | `updatedAtTimestamp` | string | When the request last changed. | | `completedAtTimestamp` | string | Set once the request is `COMPLETED`. | | `message` | string | Message from the analyst, if any. | ## Errors | Code | Meaning | |---|---| | 404 | Request not found or not owned by the caller |

Glossary and document types

Term Meaning
Property A real estate asset in SCC. Its numeric propertyId (for example 123456) is used for uploads and orders.
Parcel / APN A legally defined piece of land. The APN (Assessor's Parcel Number) is parcelId; countyId is the county's 5-digit FIPS code.

Document types

Values you can send as type to uploadDocument, and may see in documents[].type on an order.

Value Document
RENT_ROLL Rent roll: unit or tenant list with rents and lease dates
OPERATING_STATEMENT Operating statement, such as a T12 or annual income and expense statement
BUDGET Operating budget
DEVELOPMENT_BUDGET Construction or development budget
BALANCE_SHEET Balance sheet
BANK_STATEMENT Bank statement
TAX_RETURN Tax return
GUARANTOR_FINANCIAL_STATEMENT Guarantor's personal or company financials
HOTEL_OPERATING_METRICS Hotel performance data (occupancy, ADR, RevPAR)
INFO_MEMO Offering memorandum (OM) for a property
LOAN_INFO_MEMO Loan offering or credit memo
APPRAISAL_REPORT Appraisal
INSPECTION_REPORT Property condition or site inspection report
SITE_IMAGES Property photos
LEASE_AGREEMENT Lease
LOAN_AGREEMENT Loan agreement
GUARANTY Guaranty
CASH_MANAGEMENT_AGREEMENT Cash management agreement
MORTGAGE_STATEMENT Mortgage statement
PROPERTY_PURCHASE_AGREEMENT Purchase and sale agreement
INSURANCE_POLICY Insurance policy
INSURANCE_AGREEMENT Insurance agreement
INSURANCE_FORM Other insurance form
ACORD ACORD insurance certificate
PAYMENT_APPLICATION Construction draw payment application
INVOICE Invoice
LIEN_WAIVER Lien waiver
ADDITIONAL_FORM Additional form
GENERATED A document SCC generated
OTHER Anything else, or when you're not sure
This is the plain-text version of this page, the form AI agents read.
Copy as text
# Smart Capital Center API

> Find a property by address, register it, upload its documents and order a valuation or a loan quote. Built for AI agents and developers.

## Start here (agents read this first)

- **Base URL:** `https://app.smartcapitalcenter.com`
- **Version:** all endpoints are under `/api/v2/`.
- **Auth:** send `X-API-KEY: <key>` on every `/api/v2/public/*` call. No key yet? See *Set up access* below.
- **Per-operation pages:** `https://smartcapitalcenter.com/api-docs/<operation-slug>` (one HTML page per operation, slugs listed under Operations below). Read the one you need instead of loading the full OpenAPI file.
- **Operation index:** this page, `https://smartcapitalcenter.com/api-docs` (the Operations section lists every call).
- **OpenAPI schema:** `https://app.smartcapitalcenter.com/api/api-docs/public-valuation` (use for SDK generation; too large to load into context)

## Which endpoint to call

1. **The user has a street address and wants a value or a loan quote** → `searchParcels` → `createProperty` → `createOrder`
2. **The user has documents for the property** → `uploadDocument` → `createOrder`
3. **An order was placed and the user wants the result** → `getOrder`
4. **The user has a county id and parcel id (APN)** → `createProperty` → `createOrder`
5. **There is no API key yet** → login or register → `createApiKey`

## Rules for every call

1. **Authenticate with `X-API-KEY`.** Every `/api/v2/public/*` call takes the `X-API-KEY` header. Bearer tokens are only needed to create the first key; the API key calls accept either.
2. **Never expose secrets.** Do not repeat API keys, access tokens, refresh tokens or passwords back to the user or into logs. Mask them (`sq_****`).
3. **Confirm before spending money.** A `FULL` valuation charges $350. Name the property and the price and wait for an explicit yes. Never create or guess a `cardToken`.
4. **Confirm before destructive or account-level actions.** That includes `deleteApiKey` and `register`.
5. **Refresh tokens are single use.** Store the new pair immediately. Reusing an old refresh token signs the user out everywhere.
6. **Read the HTTP status code.** Errors come back as real 4xx or 5xx codes with a `message` that explains why.
7. **Poll politely.** Check an order with `getOrder` at most once a minute.
8. **Ask instead of choosing for the user** when a search returns several parcels.

## Workflows

### Value a property from an address

```
searchParcels → confirm the parcel with the user → createProperty → optional: uploadDocument for each document → confirm order type and cost → createOrder → getOrder until COMPLETED or REJECTED
```

### Set up access from nothing

```
register or login → createApiKey (Bearer token) → use X-API-KEY from then on
```

## Response envelope

Every response uses the same wrapper. Failures return a real HTTP error code; read `message` for the reason.

```json
{ "status": "success", "data": { }, "message": null, "code": null }
```

## Errors

| Code | Meaning | What to do |
|---|---|---|
| 400 | The request is invalid: a required field is missing, a format is wrong, or an enum value isn't allowed. | Fix the request using `message`. Do not retry unchanged. |
| 401 | The API key is missing or invalid, the credentials are wrong, or a refresh token was reused. | Check the header. For credential problems, tell the user. Never retry a refresh. |
| 402 | The card charge for a `FULL` valuation failed. | Tell the user. Do not retry with the same card token unless they ask. |
| 403 | The API key belongs to another user. | Stop and tell the user. |
| 404 | The property, parcel, request or API key does not exist, or the property or request belongs to another user. | Check the id; look it up again if needed. |
| 409 | An account with this email already exists. | Use `login` instead. |
| 429 | Too many sign-ups from this IP address. | Wait before calling `register` again. Do not loop. |
| 500 | Something failed on SCC's side. | Retry once after a short wait, then report the `message` and `code` to the user. |

## Operations

### Get access

- [`register`](https://smartcapitalcenter.com/api-docs/register): `POST /api/v2/auth/register`. Creates a new evaluation account and returns an access token and refresh token right away. No confirmation email is sent, so the account works immediately.
- [`login`](https://smartcapitalcenter.com/api-docs/login): `POST /api/v2/auth/login`. Exchanges an email and password for a short-lived access token and a long-lived refresh token.
- [`refresh`](https://smartcapitalcenter.com/api-docs/refresh): `POST /api/v2/auth/refresh`. Trades a refresh token for a new access token and a new refresh token. The old refresh token stops working immediately.
- [`createApiKey`](https://smartcapitalcenter.com/api-docs/create-api-key): `POST /api/v2/public/api-keys`. Creates a named API key for the signed-in user. The key goes in the `X-API-KEY` header on every other call.
- [`getUserApiKeys`](https://smartcapitalcenter.com/api-docs/get-user-api-keys): `GET /api/v2/public/api-keys`. Lists the active API keys for the authenticated user.
- [`deleteApiKey`](https://smartcapitalcenter.com/api-docs/delete-api-key): `DELETE /api/v2/public/api-keys/{id}`. Deactivates one of the user's API keys. Anything using that key stops working.

### Value a property

- [`searchParcels`](https://smartcapitalcenter.com/api-docs/search-parcels): `GET /api/v2/public/valuation/parcels`. Looks up a street address and returns the land parcels at that location. Each parcel has the `countyId` and `parcelId` needed to create a property.
- [`createProperty`](https://smartcapitalcenter.com/api-docs/create-property): `POST /api/v2/public/valuation/property`. Registers a parcel as a property in the user's account and returns its numeric `propertyId`.
- [`uploadDocument`](https://smartcapitalcenter.com/api-docs/upload-document): `POST /api/v2/public/valuation/upload-to-property/{propertyId}`. Uploads a document, such as a rent roll or operating statement, and attaches it to a property. Use the returned document id in `createOrder`.
- [`createOrder`](https://smartcapitalcenter.com/api-docs/create-order): `POST /api/v2/public/valuation/order`. Requests a full valuation (`FULL`) or a loan quote (`LOAN`) for a property the user owns.
- [`getOrder`](https://smartcapitalcenter.com/api-docs/get-order): `GET /api/v2/public/valuation/order/{id}`. Returns a valuation or loan-quote request created by `createOrder`, with its current status. Only the user who placed the order can read it.

## Glossary

| Term | Meaning |
|---|---|
| Property | A real estate asset in SCC. Its numeric `propertyId` (for example `123456`) is used for uploads and orders. |
| Parcel / APN | A legally defined piece of land. The APN (Assessor's Parcel Number) is `parcelId`; `countyId` is the county's 5-digit FIPS code. |

## Document types

Values you can send as `type` to `uploadDocument`, and may see in `documents[].type` on an order.

| Value | Document |
|---|---|
| `RENT_ROLL` | Rent roll: unit or tenant list with rents and lease dates |
| `OPERATING_STATEMENT` | Operating statement, such as a T12 or annual income and expense statement |
| `BUDGET` | Operating budget |
| `DEVELOPMENT_BUDGET` | Construction or development budget |
| `BALANCE_SHEET` | Balance sheet |
| `BANK_STATEMENT` | Bank statement |
| `TAX_RETURN` | Tax return |
| `GUARANTOR_FINANCIAL_STATEMENT` | Guarantor's personal or company financials |
| `HOTEL_OPERATING_METRICS` | Hotel performance data (occupancy, ADR, RevPAR) |
| `INFO_MEMO` | Offering memorandum (OM) for a property |
| `LOAN_INFO_MEMO` | Loan offering or credit memo |
| `APPRAISAL_REPORT` | Appraisal |
| `INSPECTION_REPORT` | Property condition or site inspection report |
| `SITE_IMAGES` | Property photos |
| `LEASE_AGREEMENT` | Lease |
| `LOAN_AGREEMENT` | Loan agreement |
| `GUARANTY` | Guaranty |
| `CASH_MANAGEMENT_AGREEMENT` | Cash management agreement |
| `MORTGAGE_STATEMENT` | Mortgage statement |
| `PROPERTY_PURCHASE_AGREEMENT` | Purchase and sale agreement |
| `INSURANCE_POLICY` | Insurance policy |
| `INSURANCE_AGREEMENT` | Insurance agreement |
| `INSURANCE_FORM` | Other insurance form |
| `ACORD` | ACORD insurance certificate |
| `PAYMENT_APPLICATION` | Construction draw payment application |
| `INVOICE` | Invoice |
| `LIEN_WAIVER` | Lien waiver |
| `ADDITIONAL_FORM` | Additional form |
| `GENERATED` | A document SCC generated |
| `OTHER` | Anything else, or when you're not sure |