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.
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. |
email and password are required.409 means the email is already registered. Switch to login and do not retry register.429 means too many sign-ups from this IP address. Wait before retrying; do not loop.curl -X POST https://app.smartcapitalcenter.com/api/v2/auth/register \
-H "Content-Type: application/json" \
-d '{"email": "agent@example.com", "password": "s3cret!"}'
200Account created — tokens issued.
{
"status": "success",
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...signature",
"refresh_token": "def50200b8f1aA-9V0pQrSt...",
"expires_in": 900,
"token_type": "Bearer"
},
"message": null,
"code": null
}
| 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>.
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.
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!. |
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.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.curl -X POST https://app.smartcapitalcenter.com/api/v2/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com", "password": "s3cret!"}'
200Authentication successful — tokens issued.
{
"status": "success",
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...signature",
"refresh_token": "def50200b8f1aA-9V0pQrSt...",
"expires_in": 900,
"token_type": "Bearer"
},
"message": null,
"code": null
}
| 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.
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.
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. |
refresh_token before doing anything else.401. Never retry a refresh with a token you have already sent.curl -X POST https://app.smartcapitalcenter.com/api/v2/auth/refresh \
-H "Content-Type: application/json" \
-d '{"refresh_token": "def50200..."}'
200Rotation 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
}
| 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.
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.
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. |
register or login in the Authorization header.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.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}'
200API 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. |
| Code | Meaning |
|---|---|
| 400 | Invalid request |
| 401 | Missing or invalid credentials |
Next: Use X-API-KEY: <key> on all /api/v2/public/* calls.
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.
curl https://app.smartcapitalcenter.com/api/v2/public/api-keys \
-H "X-API-KEY: $SCC_API_KEY"
200List 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.
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.
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id |
path | integer | yes | ID of the API key to delete. |
403 means the key belongs to another user. 404 means the id does not exist.curl -X DELETE https://app.smartcapitalcenter.com/api/v2/public/api-keys/42 \
-H "X-API-KEY: $SCC_API_KEY"
200API key deleted successfully.
Standard envelope: {"status", "data", "message", "code"}.
| Code | Meaning |
|---|---|
| 403 | Access denied - API key belongs to another user |
| 404 | API key not found |
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.
| Name | In | Type | Required | Description |
|---|---|---|---|---|
address |
query | string | yes | Full street address, including city, state and ZIP when known. |
matchedAddress is the address the geocoder actually matched. If it differs meaningfully from what the user typed, confirm before continuing.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.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"
200OK.
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. |
| 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.
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.
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. |
propertyId. Uploads and orders need it.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"}'
200OK.
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. |
| Code | Meaning |
|---|---|
| 400 | Validation error |
| 404 | Parcel not found |
Next: uploadDocument if the user has documents for the property, otherwise createOrder.
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.
| 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). |
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. |
data.id and pass it in createOrder documentIds for the same property.type when you know it, so the right extraction runs. Use OTHER when unsure.file may also be sent as a query parameter.404 means the property does not exist or belongs to another user.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"
202Document 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. |
| 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.
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.
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. |
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.data.id is the request id. Check progress with getOrder, at most once a minute, until status is COMPLETED or REJECTED.402 means the card charge failed. Tell the user; do not retry with the same card token unless they ask.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]}'
200OK.
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 | — |
| 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.
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.
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id |
path | integer | yes | Request id (data.id from createOrder). |
status is COMPLETED or REJECTED; both are final. Report statusLabel and any message to the user.404 means the request does not exist or belongs to another user.curl https://app.smartcapitalcenter.com/api/v2/public/valuation/order/98765 \
-H "X-API-KEY: $SCC_API_KEY"
200Request 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. |
| Code | Meaning |
|---|---|
| 404 | Request not found or not owned by the caller |