---
updatedAt: 2026-05-19T04:01:14.000Z
---

Fetch the complete documentation index at: https://docs.usestable.com/llms.txt. Use this file to discover all available pages before exploring further. Append .md to any documentation page URL to get its markdown version.

# Create and Onboard a New CMRA Location

Learn how to add a new CMRA Location to your existing Organization and authorize it to receive mail.

> 📘 This guide covers **CMRA** (Commercial Mail Receiving Agency) locations only. To create a **registered agent** location, see [Create a Registered Agent Location](https://docs.usestable.com/docs/create-a-registered-agent-location) instead.

Learn how to add a new CMRA `Location` to your existing `Organization` and authorize it to receive mail.

# Overview

The **United States Postal Service** requires Stable to store a signed copy of [**USPS Form 1583**](https://support.usestable.com/en/articles/8236359-what-is-the-usps-1583-form) in order to authorize mail reception at a CMRA [Location](https://docs.usestable.com/docs/the-location-object). This guide walks you through the complete process of creating a CMRA `Location` and submitting the required documentation via the Stable API.

You'll learn how to:

* Create a new CMRA `Location`
* Submit **USPS Form 1583** information programmatically
* Upload identification documents securely
* Generate signature URLs for document signing
* Monitor the onboarding progress via webhooks

Registered agent locations follow a different flow that does not require USPS Form 1583 or document uploads. If you need a registered agent, head to [Create a Registered Agent Location](https://docs.usestable.com/docs/create-a-registered-agent-location).

# Prerequisites

Before you begin, you'll need:

* [A Stable API key](https://docs.usestable.com/reference/authentication)
* A CMRA [location code](https://docs.usestable.com/docs/location-codes) (e.g. `SFO1`, `ATL3`). Registered agent state codes (e.g. `WY`, `DE`) are **not** valid for this flow
* Access to the identification documents of the applicant:
  * [Primary ID](https://support.usestable.com/en/articles/8236386-what-is-a-primary-id) (government-issued photo ID)
  * [Secondary ID](https://support.usestable.com/en/articles/8236383-what-is-a-secondary-id) (proof of address)
  * [Verification Photo](https://support.usestable.com/en/articles/8236407-how-do-i-take-an-id-verification-image) (selfie)
* Basic understanding of REST APIs and HTTP requests
* A way to receive webhook notifications (recommended)

> 📘 **Keep Your Applicant's Documents Ready**
>
> Having all required documents prepared in advance will make the onboarding process smoother. For details on acceptable forms of ID, see our [Primary ID](https://support.usestable.com/en/articles/8236386-what-is-a-primary-id), [Secondary ID](https://support.usestable.com/en/articles/8236383-what-is-a-secondary-id), and [Verification Photo](https://support.usestable.com/en/articles/8236407-how-do-i-take-an-id-verification-image) support articles.

# Authentication

All API requests require authentication using your API key in the `x-api-key` header:

```bash cURL
curl -H "x-api-key: your-api-key" https://api.usestable.com/v1/...
```

```javascript JavaScript
const fetch = require('node-fetch');

const url = 'https://api.usestable.com/v1/locations';
const options = {
  headers: {
    'x-api-key': 'your-api-key',
    'Content-Type': 'application/json',
  },
  // ...
};

fetch(url, options)
  .then(response => console.log('Response:', response.json()))
  .catch(error => console.error('Error:', error));
```

```python Python
import requests

url = 'https://api.usestable.com/v1/...'
headers = {
    'x-api-key': 'your-api-key',
    'Content-Type': 'application/json',
}

response = requests.get(url, headers=headers)

if response.ok:
    print(response.json())
else:
    print(f"Error: {response.status_code}, {response.text}")
```

<Callout icon="🔒" theme="default">
  ### **API Key Security**

  Keep your API key secure and never expose it in client-side code. All API requests should be made from your backend services.
</Callout>

# Process Overview

The CMRA `Location` onboarding process follows these steps:

1. Create a new CMRA `Location` in your `Organization`
2. Upload **USPS Form 1583 information** using the `prefill` endpoint
3. Upload required identification documents:
   1. Primary ID (government-issued photo ID)
   2. Secondary ID (proof of address)
   3. Verification photo (selfie)
4. Create a signature packet
5. Direct your user to the signature URL and complete form signature
6. Monitor onboarding status via webhooks

Each step must be completed in order, and you'll receive webhook notifications as your `Location` progresses through the onboarding stages. You can also [query the onboarding status via the API](https://docs.usestable.com/reference/getlocationgetv1locationsid).

## Step 1: Creating a CMRA Location

Start by [creating a new Location](https://docs.usestable.com/reference/createlocationpostv1locations-2) that will receive mail.

* You'll need to specify a CMRA [location code](https://docs.usestable.com/docs/location-codes) (an IATA-style code such as `SFO1`, `ATL3`, or `BOS1`) from our list of available facilities.
* You should also decide whether to enable `autoScan`. When `autoScan` is enabled, every piece of mail received at this `Location` will have its contents opened, scanned, and uploaded, in addition to the outer envelope.

> 📘 **CMRA codes only**
>
> The `locationCode` for a CMRA must be one of the IATA-style codes listed on the [Location codes](https://docs.usestable.com/docs/location-codes) page (for example `SFO1`). Passing a 2-letter US state code (for example `WY`) will route the request through the registered agent flow instead. See [Create a Registered Agent Location](https://docs.usestable.com/docs/create-a-registered-agent-location).

```bash cURL
curl -X POST https://api.usestable.com/v1/locations \
  -H "x-api-key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "locationCode": "SFO1",
    "autoScan": true
  }'
```

```javascript JavaScript
const fetch = require('node-fetch');

const url = 'https://api.usestable.com/v1/locations';
const options = {
  method: 'POST',
  headers: {
    'x-api-key': 'your-api-key',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    locationCode: 'SFO1',
    autoScan: true,
  }),
};

fetch(url, options)
  .then(response => console.log('Response:', response.json()))
  .catch(error => console.error('Error:', error));
```

```python Python
import requests

url = 'https://api.usestable.com/v1/locations'
headers = {
    'x-api-key': 'your-api-key',
    'Content-Type': 'application/json',
}
payload = {
    'locationCode': 'SFO1',
    'autoScan': True,
}

response = requests.post(url, headers=headers, json=payload)

if response.ok:
    print(response.json())
else:
    print(f"Error: {response.status_code}, {response.text}")
```

### Response

```json JSON
{
  "id": "6510b338-57d9-4aac-8e84-fb047ae42e86",
  "status": "active",
  "address": {
    "line1": "2261 Market Street",
    "line2": "#4962",
    "city": "San Francisco",
    "state": "CA",
    "postalCode": "94114"
  },
  "type": "cmra",
  "onboarding": {
    "status": "authorize"
  },
  "metadata": null
}
```

> 📘 **Location Status**
>
> For CMRA locations, the top-level `status` is returned as `active` immediately on creation. The `onboarding.status` will be `authorize`, indicating the location is ready for **USPS Form 1583** submission. See [the Location object](https://docs.usestable.com/docs/the-location-object) for the full status reference.

## Step 2: Submit USPS Form 1583 Information

After creating your `Location`, submit the required **USPS Form 1583** information [using the prefill endpoint](https://docs.usestable.com/reference/onboardlocationprefillpostv1locationsidonboardprefill). This step pre-populates the form with your user's information.

```bash cURL
curl -X POST https://api.usestable.com/v1/locations/6510b338-57d9-4aac-8e84-fb047ae42e86/onboard/prefill \
  -H "x-api-key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "submissionType": "business",
    "legalBusinessName": "Happy Inc.",
    "phone": "4151112222",
    "placeOfRegistration": "Delaware",
    "businessType": "Technology",
    "firstName": "Jane",
    "lastName": "Doe",
    "email": "jane@example.com",
    "officerRole": "Founder",
    "isCompanyOfficerConfirmed": true,
    "primaryIdType": "passport",
    "primaryIdNumber": "987654321",
    "primaryIdIssuingEntity": "United States",
    "primaryIdExpirationDate": "2035-12-31",
    "secondaryIdType": "utility_bill",
    "secondaryIdAddress": {
      "line1": "456 Elm Street",
      "line2": "Suite 200",
      "city": "Austin",
      "state": "Texas",
      "postalCode": "73301",
      "country": "US"
    }
  }'
```

```javascript JavaScript
const fetch = require('node-fetch');

const locationId = 'your-location-id';
const url = `https://api.usestable.com/v1/locations/${locationId}/onboard/prefill`;

const body = {
  submissionType: 'business',
  legalBusinessName: 'Happy Inc.',
  phone: '4151112222',
  placeOfRegistration: 'Delaware',
  businessType: 'Technology',
  firstName: 'Jane',
  lastName: 'Doe',
  email: 'jane@example.com',
  officerRole: 'Founder',
  isCompanyOfficerConfirmed: true,
  primaryIdType: 'passport',
  primaryIdNumber: '987654321',
  primaryIdIssuingEntity: 'United States',
  primaryIdExpirationDate: '2035-12-31',
  secondaryIdType: 'utility_bill',
  secondaryIdAddress: {
    line1: '456 Elm Street',
    line2: 'Suite 200',
    city: 'Austin',
    state: 'Texas',
    country: 'US',
    postalCode: '73301',
  },
};

const options = {
  method: 'POST',
  headers: {
    'x-api-key': 'your-api-key',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(body),
};

fetch(url, options)
  .then(response => response.json())
  .then(data => console.log('Response:', data))
  .catch(error => console.error('Error:', error));
```

```python Python
import requests

location_id = 'your-location-id'
url = f'https://api.usestable.com/v1/locations/{location_id}/onboard/prefill'

body = {
    "submissionType": "business",
    "legalBusinessName": "Happy Inc.",
    "phone": "4151112222",
    "placeOfRegistration": "Delaware",
    "businessType": "Technology",
    "firstName": "Jane",
    "lastName": "Doe",
    "email": "jane@example.com",
    "officerRole": "Founder",
    "isCompanyOfficerConfirmed": True,
    "primaryIdType": "passport",
    "primaryIdNumber": "987654321",
    "primaryIdIssuingEntity": "United States",
    "primaryIdExpirationDate": "2035-12-31",
    "secondaryIdType": "utility_bill",
    "secondaryIdAddress": {
        "line1": "456 Elm Street",
        "line2": "Suite 200",
        "city": "Austin",
        "state": "Texas",
        "country": "US",
        "postalCode": "73301"
    }
}

headers = {
    "x-api-key": "your-api-key",
    "Content-Type": "application/json"
}

response = requests.post(url, headers=headers, json=body)

if response.ok:
    print("Response:", response.json())
else:
    print(f"Error: {response.status_code}, {response.text}")
```

### Response

Note the `url` and `expiresAt` fields.

* The `url` is a link to the partially filled **USPS 1583 Form**. You can use this `url` to continue and even complete the `Location` onboarding process.
* You'll want to check the `expiresAt` field, as it indicates the deadline by which the `url` will remain valid. Either have the user complete the onboarding process before this time is up, or [request a new link](https://docs.usestable.com/reference/getonboardlocationsignaturepacketgetv1locationsidonboardsignature-packet) if this one expires.

```json JSON
{
  "id": "9f2f1342-630e-48ad-a2e3-bca9f126c56e",
  "expiresAt": "2024-11-06T00:00:00.000Z",
  "url": "https://dashboard.usestable.com/location/6510b338-57d9-4aac-8e84-fb047ae42e86/onboard/authorize/business?key=bd1a413ba8709e6257d2b07e"
}
```

<Callout icon="👥" theme="default">
  ### **Manual Form Completion URL**

  The `url` returned in the response is only needed if your end user will be completing some form fields manually. When all data is submitted programmatically through the API, you can ignore this `url` and proceed directly to document uploads.
</Callout>

## Step 3: Upload Required Documents

After submitting the **USPS Form 1583** information, you'll need to upload three required documents. For each document, this is a two-step process:

* Get a secure upload URL for the specific document type
* Upload the document using the provided URL

### Getting Upload URLs

For each document you want to upload, [first request a pre-signed upload URL](https://docs.usestable.com/reference/onboardlocationuploadurlspostv1locationsidonboardupload-urls). This URL allows secure direct upload to our storage system.

```bash cURL
curl -X POST https://api.usestable.com/v1/locations/6510b338-57d9-4aac-8e84-fb047ae42e86/onboard/upload-urls \
  -H "x-api-key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "primary",
    "fileType": "jpg"
  }'
```

```javascript JavaScript
const fetch = require('node-fetch');

const locationId = 'your-location-id';
const url = `https://api.usestable.com/v1/locations/${locationId}/onboard/upload-urls`;

const body = {
  type: 'primary',
  fileType: 'jpg',
};

const options = {
  method: 'POST',
  headers: {
    'x-api-key': 'your-api-key',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(body),
};

fetch(url, options)
  .then(response => response.json())
  .then(data => console.log('Response:', data))
  .catch(error => console.error('Error:', error));
```

```python Python
import requests

location_id = 'your-location-id'
url = f'https://api.usestable.com/v1/locations/{location_id}/onboard/upload-urls'

body = {
    "type": "primary",
    "fileType": "jpg",
}

headers = {
    "x-api-key": "your-api-key",
    "Content-Type": "application/json"
}

response = requests.post(url, headers=headers, json=body)

if response.ok:
    print("Response:", response.json())
else:
    print(f"Error: {response.status_code}, {response.text}")
```

### Upload URL Response

```json JSON
{
  "uploadUrl": "..."
}
```

> ⚠️ **URL Expiration**
>
> Upload URLs expire after **2 minutes**. Always request a new URL immediately before uploading each document.

### Uploading Documents

Use the pre-signed URL to upload your document. Make sure to set the correct content type header for your file:

```bash cURL
curl -X PUT "UPLOAD_URL_FROM_PREVIOUS_RESPONSE" \
  -H "Content-Type: image/jpeg" \
  --data-binary @/path/to/primary-id.jpg
```

```javascript JavaScript
const fetch = require('node-fetch');
const fs = require('fs');

const uploadUrl = 'UPLOAD_URL_FROM_PREVIOUS_RESPONSE';
const filePath = '/path/to/primary-id.jpg';

const fileData = fs.readFileSync(filePath);

const options = {
  method: 'PUT',
  headers: {
    'Content-Type': 'image/jpeg',
  },
  body: fileData,
};

fetch(uploadUrl, options)
  .then(response => {
    if (response.ok) {
      console.log('File uploaded successfully');
    } else {
      console.error('Upload failed:', response.status, response.statusText);
    }
  })
  .catch(error => console.error('Error:', error));
```

```python Python
import requests

upload_url = 'UPLOAD_URL_FROM_PREVIOUS_RESPONSE'
file_path = '/path/to/primary-id.jpg'

file_data = open(file_path, 'rb').read()

headers = {
    "Content-Type": "image/jpeg"
}

response = requests.put(upload_url, headers=headers, data=file_data)

if response.ok:
    print("File uploaded successfully")
else:
    print(f"Upload failed: {response.status_code}, {response.text}")
```

### Supported File Types

You can upload documents in any of these formats:

* Images: `jpg`, `jpeg`, `png`, `heic`
* Documents: `pdf` (must not be password protected)

### Required Documents

You'll need to repeat the upload process for each of these required documents:

* [Primary ID](https://support.usestable.com/en/articles/8236386-what-is-a-primary-id) (`type: "primary"`):
  * A government-issued photo ID like a passport or driver's license
  * Must clearly show the applicant's photo and name
* [Secondary ID](https://support.usestable.com/en/articles/8236383-what-is-a-secondary-id) (`type: "secondary"`):
  * A document proving the applicant's address
  * Must show the same address provided in the **USPS Form 1583** information
* [Verification Photo](https://support.usestable.com/en/articles/8236407-how-do-i-take-an-id-verification-image) (`type: "selfie"`):
  * A clear photo of the applicant
  * Should match the photo on the primary ID

> 📘 **Multiple Uploads**
>
> If you upload multiple files for the same document type (for example, both a `jpg` and `pdf` version of a primary ID), we'll use the most recently uploaded version when creating the signature packet.

### Successful Upload Response

A successful upload will return an HTTP `200` status code with a response like this:

```
HTTP/1.1 200 OK
x-amz-request-id: 7B4A0FABBG9ADFCA
Date: Wed, 06 Nov 2024 20:00:00 GMT
ETag: "828ef3fdfa96f00ad9f27c383fc9ac7f"
Content-Length: 0
```

### Unsuccessful Upload Response - Expired URL

```xml XML
<Error>
  <Code>AccessDenied</Code>
  <Message>Request has expired</Message>
  <Expires>2024-12-05T21:23:35Z</Expires>
  <ServerTime>2024-12-05T21:24:01Z</ServerTime>
  <RequestId>PSH8ANGEQMG1FP0M</RequestId>
  <HostId>nhWJL3qKT6tEuqHIF4KdemO3Kuui41PYml2nrXaJS+NAP7JEZjYL/ZdX8GChK02painc8Ac3zKk=</HostId>
</Error>
```

<Callout icon="🔁" theme="default">
  ### **Failed Uploads**

  If an upload fails or the pre-signed upload URL expires, request a new upload URL and try again.
</Callout>

## Step 4: Creating a Signature Packet

Once you've uploaded all required documents, you'll need to [create a signature packet](https://docs.usestable.com/reference/createonboardlocationsignaturepacketpostv1locationsidonboardsignature-packet). The signature packet combines your uploaded documents with the **USPS Form 1583** information into a single package for electronic signature.

### Creating the Packet

Send a `POST` request to create the signature packet:

```bash cURL
curl -X POST https://api.usestable.com/v1/locations/6510b338-57d9-4aac-8e84-fb047ae42e86/onboard/signature-packet \
  -H "x-api-key: your-api-key"
```

```javascript JavaScript
const fetch = require('node-fetch');

const locationId = 'your-location-id';
const url = `https://api.usestable.com/v1/locations/${locationId}/onboard/signature-packet`;

const options = {
  method: 'POST',
  headers: {
    'x-api-key': 'your-api-key',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(data => console.log('Response:', data))
  .catch(error => console.error('Error:', error));
```

```python Python
import requests

location_id = 'your-location-id'
url = f'https://api.usestable.com/v1/locations/{location_id}/onboard/signature-packet'

headers = {
    "x-api-key": "your-api-key",
}

response = requests.post(url, headers=headers)

if response.ok:
    print("Response:", response.json())
else:
    print(f"Error: {response.status_code}, {response.text}")
```

```json JSON
{
  "id": "24f15197-118d-457c-8995-522164cb144d",
  "expiresAt": "2025-01-06T00:00:00Z",
  "url": "https://dashboard.usestable.com/location/6510b338-57d9-4aac-8e84-fb047ae42e86/onboard/authorize/business?embedded=true&key=19F781"
}
```

The response includes a URL that leads to a white-labeled signing experience you can embed within your application's flow.

> 📘 **Location Status**
>
> Creating a **Signature Packet** will change your `Location`'s `onboarding.status` from `authorize` to `sign`. This indicates that all required documents have been uploaded and the `Location` is ready for signature collection.

### Retrieving an Existing Packet

You can [retrieve an existing signature packet](https://docs.usestable.com/reference/getonboardlocationsignaturepacketgetv1locationsidonboardsignature-packet) if your previous `url` has expired.

```bash cURL
curl -X GET https://api.usestable.com/v1/locations/6510b338-57d9-4aac-8e84-fb047ae42e86/onboard/signature-packet \
  -H "x-api-key: your-api-key"
```

```javascript JavaScript
const fetch = require('node-fetch');

const locationId = 'your-location-id';
const url = `https://api.usestable.com/v1/locations/${locationId}/onboard/signature-packet`;

const options = {
  method: 'GET',
  headers: {
    'x-api-key': 'your-api-key',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(data => console.log('Response:', data))
  .catch(error => console.error('Error:', error));
```

```python Python
import requests

location_id = 'your-location-id'
url = f'https://api.usestable.com/v1/locations/{location_id}/onboard/signature-packet'

headers = {
    "x-api-key": "your-api-key",
}

response = requests.get(url, headers=headers)

if response.ok:
    print("Response:", response.json())
else:
    print(f"Error: {response.status_code}, {response.text}")
```

```json JSON
{
  "id": "24f15197-118d-457c-8995-522164cb144d",
  "expiresAt": "2025-01-06T00:00:00Z",
  "url": "https://dashboard.usestable.com/location/6510b338-57d9-4aac-8e84-fb047ae42e86/onboard/authorize/business?embedded=true&key=19F781"
}
```

### Customizing the Signature Interface

The signature URL returned by the API includes `embedded=true` by default:

```json JSON
{
  "url": "https://dashboard.usestable.com/location/{id}/onboard/authorize/business?key={key}&embedded=true"
}
```

There are two available display modes:

#### `embedded=true` (default from API)

* Removes all Stable styling and chrome
* Hides navigation elements, footer, and branding
* Provides a minimal interface ideal for embedding

#### `branded=false` (optional alternative)

* Only hides the Stable logo
* Maintains standard navigation and UI elements
* Keeps Stable's styling and layout

> 📘 **Combining Multiple Modes**
>
> Adding `branded=false` to a URL that already has `embedded=true` has no effect, as `embedded=true` already provides a more comprehensive white-label experience.

### Restarting the Process

If you need to modify any submitted information after creating a signature packet, you can [delete the existing packet](https://docs.usestable.com/reference/deleteonboardlocationsignaturepacketdeletev1locationsidonboardsignature-packet) and start fresh:

```bash cURL
curl -X DELETE https://api.usestable.com/v1/locations/6510b338-57d9-4aac-8e84-fb047ae42e86/onboard/signature-packet \
  -H "x-api-key: your-api-key"
```

Deleting the signature packet allows you to:

* Upload new versions of documents
* Update **USPS Form 1583** information
* Generate a new signature URL

The response confirms the successful deletion:

```json JSON
{
  "success": true
}
```

> 📘 **Location Status**
>
> Deleting a `Location`'s **Signature Packet** will change that location's `onboarding.status` from `sign` back to `authorize`. This indicates the location requires a new signature packet before signatures can be collected.

## Step 5: Monitoring Onboarding Status

After your user signs the documents, our team performs verifications on all submitted information. You can track the progress of this verification through [Webhook notifications](https://docs.usestable.com/docs/webhooks) and direct API checks.

### Webhook Notifications

Register a webhook endpoint to receive real-time updates about the onboarding process. You'll receive notifications for important events including:

```json JSON
{
  "data": {
    "status": "active",
    "address": {
      "city": "San Francisco",
      "line1": "123 Main St",
      "line2": "#4962",
      "postalCode": "94105",
      "state": "CA"
    },
    "id": "70a3d702-bf1d-4153-8eb2-d3d889aff7f0",
    "metadata": null,
    "onboarding": {
      "status": "verify"
    },
    "type": "cmra"
  },
  "eventType": "location.onboarding.updated"
}
```

### Onboarding Status Values

Your `Location` will progress through several `onboarding.status` values during the onboarding process:

```json JSON
{
  "onboarding": {
    "status": "verify"
  }
}
```

The `status` values indicate where your `Location` is in the onboarding process:

* `authorize`: Initial state, awaiting document submission and signature
* `sign`: Documents uploaded, awaiting signature completion
* `verify`: Documents signed, undergoing manual verification
* `complete`: Onboarding completed successfully

### Document Verification

During the verification phase, our team reviews all submitted identification documents to ensure they meet USPS requirements. If any documents are rejected (for example, due to poor image quality, expired IDs, or mismatched information), the associated signature packet will be deleted, and you'll receive a webhook notification with the location's onboarding status changing from `verify` back to `authorize`. Additionally, all admins in your organization will be notified via email. When this happens, you should:

1. Upload new documents that address the rejection reason
2. Create a new signature packet
3. Have the applicant complete the signature process again

### Checking Status Manually

You can check your `Location`'s current status at any time:

```bash cURL
curl https://api.usestable.com/v1/locations/6510b338-57d9-4aac-8e84-fb047ae42e86 \
  -H "x-api-key: your-api-key"
```

```javascript JavaScript
const fetch = require('node-fetch');

const locationId = 'your-location-id';
const url = `https://api.usestable.com/v1/locations/${locationId}`;

const options = {
  method: 'GET',
  headers: {
    'x-api-key': 'your-api-key',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(data => console.log('Response:', data))
  .catch(error => console.error('Error:', error));
```

```python Python
import requests

location_id = 'your-location-id'
url = f'https://api.usestable.com/v1/locations/{location_id}'

headers = {
    "x-api-key": "your-api-key",
}

response = requests.get(url, headers=headers)

if response.ok:
    print("Response:", response.json())
else:
    print(f"Error: {response.status_code}, {response.text}")
```

### Response

```json JSON
{
  "id": "6510b338-57d9-4aac-8e84-fb047ae42e86",
  "status": "active",
  "address": {
    "line1": "2261 Market Street",
    "line2": "#4962",
    "city": "San Francisco",
    "state": "CA",
    "postalCode": "94114"
  },
  "type": "cmra",
  "onboarding": {
    "status": "complete"
  },
  "metadata": null
}
```

# Error Handling

Here's a guide to errors you might encounter during the CMRA onboarding process and how to handle them.

## Location Errors

### Location Not Found

```json JSON
{
  "status": 404,
  "message": "This location could not be found"
}
```

Solution: Verify the `Location` ID is correct.

### Invalid Location Code

```json JSON
{
  "status": 400,
  "message": "Validation error(s) when parsing body: 'locationCode must be a CMRA code (ATL3, BHM1, ...) or a registered agent jurisdiction code (AK, AL, ...). See https://docs.usestable.com/docs/location-codes for more information.'"
}
```

Solution: Use one of the supported CMRA location codes listed in the documentation. If you intended to create a registered agent location, see [Create a Registered Agent Location](https://docs.usestable.com/docs/create-a-registered-agent-location).

### Field Not Allowed for CMRA

```json JSON
{
  "status": 400,
  "message": "companyId is not allowed for CMRA locations"
}
```

Solution: The `companyId`, `additionalInformation`, and registered-agent-only fields are not allowed when creating a CMRA. Remove those fields from your request body.

## Document Upload Errors

### Pre-signed URL Expired

```xml XML
<Error>
  <Code>AccessDenied</Code>
  <Message>Request has expired</Message>
  <Expires>2024-12-05T21:23:35Z</Expires>
  <ServerTime>2024-12-05T21:24:01Z</ServerTime>
  <RequestId>PSH8ANGEQMG1FP0M</RequestId>
  <HostId>nhWJL3qKT6tEuqHIF4KdemO3Kuui41PYml2nrXaJS+NAP7JEZjYL/ZdX8GChK02painc8Ac3zKk=</HostId>
</Error>
```

Solution: Request a new upload URL and try again.

### Invalid File Type

```json JSON
{
  "status": 400,
  "message": "Validation error(s) when parsing body: 'fileType must be one of the following values: jpg, jpeg, png, heic, pdf'"
}
```

Solution: Convert the file to a supported format.

### Missing Documents

```json JSON
{
  "status": 400,
  "message": "Missing document uploads for: Secondary ID, Selfie."
}
```

Solution: Ensure all required documents are uploaded before creating the signature packet.

## USPS Form 1583 Submission Errors

### Invalid Submission Data

```json JSON
{
  "status": 400,
  "message": "primaryIdType is a required field"
}
```

Solution: Review the submission data and ensure all required fields are provided.

### Existing Signature Packet

```json JSON
{
  "status": 409,
  "message": "USPS 1583 signature packet already exists."
}
```

Solution: Delete the existing signature packet if you need to make changes.

# Best Practices

To ensure a smooth CMRA onboarding process:

* **Document Quality**
  * Ensure uploaded documents are clear and legible
  * Verify that addresses on secondary ID match the submitted information exactly
  * Make sure the verification photo clearly shows the applicant's face
* **Error Handling**
  * Implement retry logic for upload failures
  * Store the Location ID for status checking
  * Set up webhook handling for real-time status updates
* **Status Monitoring**
  * Implement webhook handlers for all onboarding status changes
  * Have a fallback mechanism to poll the status endpoint if needed
  * Keep your users informed of the verification progress