Partner API Reference

Mailed Records API

Production endpoints, deterministic configuration tests, response contracts, quotas, and error handling for partner integrations that search approved mailed-record fields.

Base URL

https://www.ratespedia.com

Authentication

Authorization: Bearer <token>

Safe setup

/api/mailed-records/test/*
GETProduction search
/api/mailed-records/search

Paginated search over approved mailed-record fields.

GETConfiguration search test
/api/mailed-records/test/search

Validates headers and filters without production data.

Configuration tests never touch production data.

Use the `/test` endpoints to validate headers, query parameters, JSON bodies, and error handling before switching to the production routes.

Partner home

updated: "2026-07-20T23:20:00Z"

Customer-facing reference for Ratespedia's read-only Mailed Records API. Use this guide to configure authentication, test your client safely, search approved mailed-record results, and handle every expected response.

Overview

The API gives approved customers a controlled, retrieval-only way to search mailed-record results. It supports two customer access paths:

  • Direct API access for server-side integrations.
  • The Mailed Records Portal for browser-based teams that should not handle API keys.

Canonical routes:

API docs: /partners/mailed-records-api
Portal:   /partners/mailed-records-portal

Base URL

https://www.ratespedia.com

Customer Setup Flow

  1. Request customer API access from Ratespedia.
  2. Store your API key only on your server.
  3. Run the configuration test endpoints first.
  4. Confirm your client handles success, validation errors, authentication errors, quota errors, and service errors.
  5. Switch to the production endpoints.
  6. Use pagination for production search results.
  7. Treat returned records as read-only. API keys cannot create, update, or delete database records.

Environments And Endpoints

Configuration tests return deterministic responses and do not read or update production records.

EnvironmentMethodPathPurpose
TestGET/api/mailed-records/test/searchValidate headers, filters, pagination handling, and error handling.
ProductionGET/api/mailed-records/searchSearch approved mailed-record results.

Read-only Contract

Customer API keys permit retrieval only. PATCH /api/mailed-records/contact and PATCH /api/mailed-records/test/contact return 405 read_only_api before authentication lookup, request-body parsing, quota accounting, or database code can run. The response includes Allow: GET and directs integrations to the production search route.

{
  "success": false,
  "error": "Mailed Records API keys support retrieval only. Use GET /api/mailed-records/search.",
  "code": "read_only_api"
}

Authenticated portal and CRM workflows are separate from customer API keys.

Authentication

Direct API requests require one API key. Send it with either supported header.

Recommended:

Authorization: Bearer <token>

Also supported:

x-api-key: <token>

Do not send both headers in the same request. Do not place API keys in browser code, URLs, screenshots, or client-side logs.

Configuration Test Endpoints

Use the search test endpoint during initial setup, credential rotation, and client changes. It validates authentication headers and query filters without touching production records.

Test responses include:

{
  "test": {
    "mode": "configuration_test",
    "header": "Authorization",
    "tokenPreview": "test...1234",
    "credentialValidated": false,
    "productionDataTouched": false
  }
}

credentialValidated: false means the test endpoint accepted the header format but did not verify that the key is active for production. Production endpoints validate the actual key.

Test Search

GET /api/mailed-records/test/search

Example:

curl -H "Authorization: Bearer $RATESPEDIA_API_KEY" \
  "https://www.ratespedia.com/api/mailed-records/test/search?state=TX&query=Main%20Street&limit=25"

Successful response:

{
  "success": true,
  "test": {
    "mode": "configuration_test",
    "header": "Authorization",
    "tokenPreview": "test...1234",
    "credentialValidated": false,
    "productionDataTouched": false
  },
  "items": [
    {
      "mailedRecordId": "11111111-1111-4111-8111-111111111111",
      "reference": "TEST-REF-0001",
      "mailhouseRef": "TEST-REF-0001",
      "owner": {
        "firstName": "Jordan",
        "lastName": "Sample",
        "address": "100 Owner Example Way",
        "city": "Austin",
        "state": "TX",
        "zip": "78701",
        "email": "jordan.sample@example.com",
        "phone": "+1 512-555-0199",
        "optInLanguage": "Configuration test consent language.",
        "trustedFormCertUrl": "https://cert.trustedform.com/example-test-certificate"
      },
      "property": {
        "address": "200 Property Example Ave",
        "city": "Austin",
        "state": "TX",
        "zip": "78701",
        "zip4": null,
        "type": "SFR",
        "marketValue": 425000,
        "purchasePrice": 315000,
        "lengthOfOwnership": 6
      },
      "loan": {
        "amount": 280000,
        "rate": 3.625,
        "lender": "Configuration Test Lender",
        "originationDate": "2021-02-01",
        "type": "CONVENTIONAL",
        "loanToValue": 65.9,
        "veteranInHousehold": false
      }
    }
  ],
  "pageInfo": {
    "limit": 25,
    "returned": 1,
    "hasNextPage": true,
    "nextCursor": "opaque-test-token"
  },
  "appliedFilters": {
    "query": "Main Street",
    "state": "TX",
    "limit": 25,
    "hasCursor": false
  }
}

Forced Test Scenarios

Use scenario to confirm your error handling before production traffic.

ScenarioResponse
okNormal success response.
emptySearch success with no items.
invalid_api_key401 invalid_api_key.
rate_limited429 rate_limited.
daily_quota_exceeded429 daily_quota_exceeded.
server_error500 search_failed.

Example:

curl -H "Authorization: Bearer $RATESPEDIA_API_KEY" \
  "https://www.ratespedia.com/api/mailed-records/test/search?scenario=rate_limited"

Production Search

GET /api/mailed-records/search

Purpose: search approved mailed-record results with filters and cursor pagination.

Query Parameters

ParameterTypeRequiredNotes
querystringNoGeneral search text for names, addresses, or broad narrowing. Maximum 120 characters.
referencestringNoReference lookup. Maximum 120 characters.
addressstringNoProperty-address lookup. Maximum 160 characters.
statestringNoTwo-letter property state abbreviation.
citystringNoProperty city. Maximum 80 characters.
zipstringNoFive-digit property ZIP code.
loanTypestringNoLoan type filter. Maximum 40 characters.
minMarketValuenumberNoMinimum property market value.
maxMarketValuenumberNoMaximum property market value.
minLoanAmountnumberNoMinimum first mortgage amount.
maxLoanAmountnumberNoMaximum first mortgage amount.
veteranInHouseholdbooleanNotrue or false.
limitintegerNoPage size. Defaults to 25; maximum is normally 50.
cursorstringNoOpaque cursor from pageInfo.nextCursor.

Production Search Example

curl -H "Authorization: Bearer $RATESPEDIA_API_KEY" \
  "https://www.ratespedia.com/api/mailed-records/search?state=TX&query=Main%20Street&limit=25"

Production Search Response

{
  "success": true,
  "items": [
    {
      "mailedRecordId": "uuid",
      "reference": "ABC123",
      "mailhouseRef": "ABC123",
      "owner": {
        "firstName": "Jane",
        "lastName": "Doe",
        "address": "123 Owner St",
        "city": "Dallas",
        "state": "TX",
        "zip": "75001",
        "email": "jane@example.com",
        "phone": "+1 555-555-0100",
        "optInLanguage": "Customer consent language.",
        "trustedFormCertUrl": "https://cert.trustedform.com/example"
      },
      "property": {
        "address": "456 Property Ave",
        "city": "Dallas",
        "state": "TX",
        "zip": "75001",
        "zip4": null,
        "type": "SFR",
        "marketValue": 450000,
        "purchasePrice": 320000,
        "lengthOfOwnership": 7
      },
      "loan": {
        "amount": 280000,
        "rate": 3.625,
        "lender": "Example Bank",
        "originationDate": "2021-02-01",
        "type": "CONVENTIONAL",
        "loanToValue": 62.2,
        "veteranInHousehold": false
      }
    }
  ],
  "pageInfo": {
    "limit": 25,
    "returned": 25,
    "hasNextPage": true,
    "nextCursor": "opaque-token"
  },
  "appliedFilters": {
    "query": "Main Street",
    "state": "TX",
    "limit": 25,
    "hasCursor": false
  }
}

Pagination

Search uses cursor pagination.

  • Read pageInfo.hasNextPage.
  • If it is true, pass pageInfo.nextCursor as the next request's cursor.
  • Treat cursors as opaque. Do not parse, edit, or store them as business identifiers.
  • Keep the same filters when requesting the next page.

Portal Access

Customers who need browser access can use:

/partners/mailed-records-portal

Use the portal when your team needs browser access without handling API keys. Ratespedia will provide the customer login or setup instructions separately.

BRONCO owns personal portal-user administration. For normal setup and recovery, BRONCO sends a one-time setup link to /partners/mailed-records-portal/setup-password. For support resets, BRONCO can assign a temporary password by Supabase Auth admin API and mark the user with ratespedia_force_password_change / ratespedia_password_reset_required in Auth app_metadata. A user with either flag can authenticate with the temporary password, but the portal redirects them to the setup-password screen and API session/search/export routes reject normal portal access with 403 password_change_required until the permanent password is saved. The setup-password API explicitly overwrites those flags to false and clears the reset metadata after the successful password update. Do not rely on omitting or deleting metadata keys in the update payload; Supabase Auth metadata updates can preserve omitted keys, which would keep the user in the setup-password loop. The portal may use client-side metadata to route a fresh temporary-password sign-in to setup-password, but existing browser sessions must ask the server before redirecting so stale session metadata cannot force a loop after the server-side flags have been cleared. The setup-password page also checks the server before rendering the form for an active browser session; if the server says the reset requirement is already cleared, the page routes the user back to the portal instead of asking for another password.

The portal also supports self-service password resets from the login screen. The Forgot Password link collects the registered portal email, sends a 6-digit verification code to active portal members, and allows a new password only after that code is verified. Reset codes are stored server-side as HMAC hashes in mailed_records_portal_password_reset_codes, expire after 15 minutes, and are consumed after success or too many failed attempts. Self-service request, delivery, confirmation failure, and success events are written to the mailed records API audit log with resetType: self_service.

Portal lookup is a two-stage disclosure flow for every organization:

  1. GET /api/mailed-records/portal/search accepts a record number only and returns only an opaque record ID. It does not return customer, property, reference, PURL, contact, consent, or loan data.
  2. A successful preview displays only 1 record found. The result requires a valid US phone before enabling Bonzo / CRM export.
  3. Full customer and loan details are returned only after the downstream CRM confirms delivery. Invalid phone, rejected delivery, timeout, or a changed preview returns no full record.

The CRM delivery payload sends the property street address, city, state, and ZIP as distinct fields. The street-address field must not contain the city, state, or ZIP. When an individual property-address component is unavailable, delivery falls back to the corresponding owner mailing-address component. ZIP values are normalized to exactly five digits at the CRM boundary. A ZIP+4 value contributes its first five digits; a standalone four-digit extension is ignored and the alternate property or owner ZIP is checked instead.

Portal searches and exports resolve the current canonical mailed_records row. An older mail reference identifies that row through mail history; it does not restore the field values from the earlier drop. The legacy export route reloads the row immediately before delivery and accepts only the newly entered phone from the browser. Name, email, consent, certificate, address, reference, PURL, and loan fields come from that server-side reload.

For controlled organizations, the preview lookup is restricted to exact approved mailed_records.customer scope rows. Export uses POST /api/mailed-records/portal/search with the previewed mailedRecordId, record number, phone, and a browser-generated UUID requestId. The server re-runs the scoped lookup and refuses delivery if it no longer matches the previewed record. A confirmed operation writes immutable delivery evidence and one billing event before returning the full record.

Reusing the same request ID with identical input returns the stored terminal result and does not post or charge twice. Reusing it with different member, previewed record, phone, or record number is rejected. A Bonzo timeout is delivery_unknown: no full record is revealed, no charge is recorded, and the request must not be automatically retried.

For a controlled organization, the separate portal PATCH .../portal/contact and POST .../portal/bonzo-export routes still return 409 controlled_search_required. The preview GET remains available but is scope-restricted and disclosure-limited. Flags-off organizations use the same limited preview and retain the separate phone-gated export route during rollout.

Portal contact and CRM delivery operations remain organization-authenticated and are not available to API-key callers.

Agency And Member Activity Attribution

Portal audit rows preserve organization ID, organization-member ID, auth-user ID, user email, and event-time organization/member labels. Controlled operation rows preserve the same labels for confirmed exports. BRONCO reads the service-role-only portal_member_activity_daily_v view to report activity by Eastern date, agency, and banker.

  • Search count: action = 'search' with HTTP 200, including valid no-match previews. Validation, authorization, rate-limit, and server failures do not count.
  • Legacy export count: action = 'export_bonzo' with HTTP 200 and confirmed downstream success.
  • Controlled export count: billing_events.event_type = 'charge' tied to a delivered operation. Failed, unknown, replayed, deduplicated, and reversed operations do not increase the metric.

The aggregate view contains staff attribution and counts only. It does not expose customer names, addresses, phones, references, record IDs, export payloads, or webhook URLs.

Error Format

All API errors use this JSON shape:

{
  "success": false,
  "error": "Human-readable message.",
  "code": "machine_readable_code"
}

Some errors may include a details object when safe to expose.

Status Codes

StatusMeaning
200Request succeeded.
400Request is malformed or failed validation.
401API key or portal authentication is missing or invalid.
405The attempted method is not available because the customer API is read-only.
429Rate limit or quota was exceeded.
500Service configuration or temporary service failure.

Error Codes

CodeStatusWhat to do
missing_api_key401Send Authorization: Bearer <token> or x-api-key: <token>.
invalid_api_key401Confirm the key with Ratespedia and retry with the correct environment.
ambiguous_authentication400Send only one supported auth header.
invalid_authorization_header401Use Authorization: Bearer <token>.
invalid_json400Send valid JSON with Content-Type: application/json.
invalid_body400Send a JSON object.
invalid_parameter400Shorten text filters to the documented limits.
invalid_zip400Use a five-digit ZIP code.
invalid_number400Use non-negative numeric filter values.
invalid_boolean400Use true or false.
invalid_integer400Use a valid page-size integer.
invalid_cursor400Restart pagination from the first page.
invalid_range400Make sure minimum filters do not exceed maximum filters.
read_only_api405Remove the write request and use GET /api/mailed-records/search.
rate_limited429Retry after at least one minute.
daily_quota_exceeded429Wait for the next quota window or contact Ratespedia.
weekly_quota_exceeded429Wait for the next quota window or contact Ratespedia.
monthly_quota_exceeded429Wait for the next quota window or contact Ratespedia.
search_failed500Retry later. Contact Ratespedia if it persists.
unexpected_error500Retry later. Contact Ratespedia if it persists.

Rate Limits And Quotas

Ratespedia enforces short-term rate limits and longer quota windows. Exact customer limits are assigned during onboarding.

Default behavior commonly used by the API:

Limit typeDefault
Search rate limit60 requests per minute
Default search page size25
Maximum search page size50

If you receive 429, slow your request rate and retry later. If you consistently hit quota limits, contact Ratespedia to review your plan.

Customer Go-Live Checklist

  1. Confirm you have the correct production base URL.
  2. Store the API key server-side only.
  3. Run GET /api/mailed-records/test/search with your client.
  4. Force test scenarios for 401, 400, 429, and 500 handling.
  5. Switch your client to production search.
  6. Confirm production pagination handling with pageInfo.nextCursor.
  7. Confirm your integration does not send write methods or contact-update payloads.
  8. Keep request and response logs that redact API keys and personal data.

Troubleshooting

SymptomChecks
401 on test endpointsConfirm the auth header exists and uses a supported format.
401 on production endpointsConfirm the API key is active and belongs to the production environment.
400 on searchCheck parameter names, ZIP format, numeric filters, booleans, and cursor freshness.
405 read_only_apiRemove the write request and use the production GET search endpoint.
Empty production search resultsBroaden filters or confirm the expected records are available to your account.
429 responsesReduce request rate or contact Ratespedia about quota.

Support

For access, quota changes, production test records, or integration support, contact Ratespedia through /partners/contact.