System Overview & Lifecycle
This API powers a fully autonomous USPTO trademark filing bot. The end-to-end flow is:
API Call: Create Applicant
│
├─── isOldApplicant: false (default) ────────────────────────────┐
│ │
▼ │
┌─────────────────────────────────────────────────────────┐ │
│ PHASE 1 — Account Creation (Automated by Bot) │ │
│ │ │
│ 1. PENDING ──────────────► 2. EMAIL_CREATED │ │
│ (API inserts row) (mailbox provisioned) │ │
│ │ │
│ 3. FORM_FILLING ─────────► 4. FORM_SUBMITTED │ │
│ (bot fills USPTO form) (form submitted) │ │
│ │ │
│ 5. EMAIL_VERIFICATION_PENDING ► 6. EMAIL_VERIFIED │ │
│ (waiting for email) (link clicked) │ │
│ │ │
│ 7. PASSWORD_SETUP ───────► 8. SECURITY_METHOD_SETUP │ │
│ (password set) (MFA enrolled) │ │
│ │ │
│ 9. ACCOUNT_CREATED 10. ACCOUNT_FAILED │ │
│ (success — ready) (error — terminal) │ │
└─────────────────────────────────────────────────────────┘ │
│ │
▼ │
┌─────────────────────────────────────────────────────────┐ isOldApplicant: true
│ PHASE 2 — ID.me Verification │◄───────────────┘
│ │ (credentials provided directly)
│ Automatic: Bot signs in, checks /tm/verify-identity │ (lifecycle = IDME_VERIFICATION_CLAIMED)
│ On success: 11. IDME_VERIFIED │
│ 48h timeout: 12. IDME_VERIF_FAILED (terminal) │
│ │
│ API claim: PUT /:id/claim-idme-verified │
│ ?isVerified=true → 13. IDME_VERIFICATION_CLAIMED │
│ Bot verifies → 11. IDME_VERIFIED or revert to 9 │
│ ?isVerified=false → 12. IDME_VERIF_FAILED (terminal) │
└─────────────────────────────────────────────────────────┘
│
▼
API Call: Create Filing (creates Application record)
│
▼
┌─────────────────────────────────────────────────────────┐
│ PHASE 3 — Trademark Filing (Automated by Bot) │
│ │
│ Filing Status: │
│ 1. PENDING ──► 2. UNDER_PROCESS ──► 3. DONE │
│ └──► 4. ERROR │
│ │
│ Bot signs in using stored credentials + TOTP, │
│ drives the multi-page USPTO wizard automatically. │
└─────────────────────────────────────────────────────────┘
Key Concepts
- Applicant — a person/entity for whom a USPTO account is created. One applicant can have many applications.
- Application — a single trademark filing tied to an applicant. Created via the master filing API.
- Company — a tenant. Each applicant belongs to a company. Companies have email domains and callback URLs.
- Lookup Codes — all enum-like fields use string codes (not database IDs). The API resolves them server-side.
- Callbacks — the bot sends webhook notifications to your registered callback URLs for status changes.
Important Rules
⚠️ Before Filing
- Applicant must exist and be
IDME_VERIFIED before filing.
- Only
PENDING applications can be edited (via PUT).
- All codes are case-insensitive.
- Country/State accept ISO2 codes OR full names.
Response Envelope (All Endpoints)
// Success
{
"IsSuccess": true,
"Data": { ... },
"Message": "Request completed successfully.",
"StatusCode": 200
}
// Error
{
"IsSuccess": false,
"Data": { "errors": [ { "path": "...", "code": "...", "message": "..." } ] },
"Message": "Validation failed",
"StatusCode": 400
}
USPTO Wizard Pages
When the bot files a trademark, it drives a multi-page USPTO wizard. Each section of your API payload maps to one or more wizard pages.
Wizard Page Sequence
| # | USPTO Wizard Page | API Section(s) | Purpose |
| 1 | Application Selection | application.typeCode | Selects "Standard" or "Less Common" type. Nearly all use "standard". |
| 2 | Owner Information | owners[] | Identifies who owns the trademark. Supports multiple owners (bot adds tabs). |
| 3 | Attorney Information | attorney | Attorney of record. Skipped entirely when attorney = null. |
| 4 | Correspondence Information | correspondence | Who receives official USPTO mail. |
| 5 | Mark Selection | mark.formatCode | Radio: Standard Character, Special Form, Sound, or Motion. |
| 6 | Standard Character (conditional) | mark.text | Only for Standard Character Mark. Single text field. |
| 7 | Stylized/Design Format (conditional) | mark.stylizedMarkTypeCode | Only for Special Form. Sub-type radio. |
| 8 | Color Claimed (conditional) | mark.colorClaimed | Only for Special Form. Yes/No color claim radio. |
| 9 | Mark Drawing (conditional) | mark.drawingFile | File upload. Bot handles color conversion panel auto. |
| 10 | Mark Details (conditional) | mark.description, mark.colorClaim | AI-generated description accepted automatically. |
| 11 | Translation | mark.translations[] | Non-English words. Empty = "No foreign words". |
| 12 | Name/Likeness Consent | mark.nameConsents[] | Living person's name/portrait. Empty = "No". |
| 13 | Goods & Services | goodsServices[] | Nice Classification class + descriptions. |
| 14 | Supporting Info (conditional) | specimen, dates | Only for basis 1A. Specimen upload. |
| 15 | Filing Basis Selection | filingBasisCode | Legal basis: 1A, 1B, 44D, 44E, or 66A. |
| 16 | Declaration & Signature | declaration | E-signature + 4 acknowledgement checkboxes. |
| 17 | Submit Overview | (terminal) | Bot saves as draft — does NOT live-submit. |
Entity Type → USPTO Owner Form
| entityTypeCode | USPTO Form Label | Identity Fields | Special Sections |
individual | Individual | firstName, lastName, countryOfCitizenshipCode | — |
sole_proprietorship | Sole Proprietorship | entityName + firstName, lastName, countryOfCitizenshipCode | — |
us_corporation | Corporation | entityName, stateOfIncorporationCode | Country auto-set to US |
us_llc | Limited Liability Company | entityName, stateOfIncorporationCode | Country auto-set to US. members[] optional (USPTO form has no members section for LLC) |
foreign_corporation | Corporation | entityName, countryOfIncorporationCode | — |
foreign_llc | Limited Liability Company | entityName, countryOfIncorporationCode | members[] optional (USPTO form has no members section for LLC) |
partnership | Partnership | entityName | Requires members[] with roleCode: "partner" |
limited_partnership | Limited Partnership | entityName, stateOfIncorporationCode | Country auto-set to US |
trust | Trust | entityName | Requires members[] with roleCode: "trustee" |
estate | Estate | entityName | Requires members[] with roleCode: "executor" |
joint_venture | Partnership | entityName | Requires members[] |
government | Other | entityName | Country auto-set to US |
other | Non-profit Association | entityName | Country auto-set to US |
💡 Key Insight
sole_proprietorship is the only entity type that requires
both entityName (business name) AND
firstName/
lastName (individual) plus
countryOfCitizenshipCode.
Mark Format → Wizard Path
| formatCode | Pages Shown | Required Fields |
Standard Character Mark | Mark Selection → Standard Character → Translation → ... | mark.text |
Special Form | Mark Selection → Stylized → Color Claimed → Drawing → Details → ... | mark.drawingFile, mark.stylizedMarkTypeCode, mark.description |
Sound Mark | Mark Selection → Drawing (audio) → ... | mark.soundFile |
Motion Mark | Mark Selection → Drawing (video) → ... | mark.motionFile |
Filing Basis → Wizard Behavior
| Code | Name | What the Bot Fills |
1A | Use in Commerce | firstUseAnywhereDate, firstUseInCommerceDate, specimen data |
1B | Intent to Use | Radio only — no additional data |
44D | Foreign Application | foreignApplication.countryCode, .serialNumber, .filingDate |
44E | Foreign Registration | foreignRegistration.countryCode, .registrationNumber, dates, certificate |
66A | Madrid Protocol | Radio only — no additional data |
Address Rules
- Mailing Address — always shown. Primary public address on trademark record.
- Domicile Address — only shown when "same as mailing" is unchecked.
- When
country = "United States" → State dropdown appears and must be filled.
- When
country ≠ "United States" → State field is hidden.
POST /applicants/create-applicant
Creates a new applicant record. Supports two modes controlled by the isOldApplicant flag:
- New applicant (
isOldApplicant: false, default) — provisions a fresh USPTO mailbox. Bot picks up automatically and begins Phase 1 account creation.
- Old applicant (
isOldApplicant: true) — tenant supplies existing USPTO credentials directly. Mailbox provisioning is skipped. Bot picks up at Phase 2 (claim verification → filing) immediately.
POST
/api/v1/applicants/create-applicant
Request Body — New Applicant (isOldApplicant: false)
{
"companyId": 1,
"customerId": 1014,
"nameTitle": "Mr",
"firstName": "Mike",
"middleName": null,
"lastName": "Jacob",
"suffix": null,
"emailAddress": "[email protected]",
"isOldApplicant": false,
"emailDomain": "trademarkluv.com",
"pseudo": null,
"botCode": null,
"country": "US",
"state": "TX",
"cityId": null,
"streetAddress1": "411 Spruce St",
"streetAddress2": null,
"zipCode": "78701",
"phone": {
"dialCode": "1",
"countryCode": "US",
"number": "2179856987"
}
}
Request Body — Old Applicant (isOldApplicant: true)
{
"companyId": 1,
"customerId": 1014,
"nameTitle": "Mr",
"firstName": "Mike",
"middleName": null,
"lastName": "Jacob",
"suffix": null,
"emailAddress": "[email protected]",
"isOldApplicant": true,
"usptoAccountEmail": "[email protected]",
"usptoAccountPassword": "Tr@deMark#9821",
"mfaSecret": "JBSWY3DPEHPK3PXP",
"botCode": null,
"country": "US",
"state": "TX",
"cityId": null,
"streetAddress1": "411 Spruce St",
"streetAddress2": null,
"zipCode": "78701",
"phone": {
"dialCode": "1",
"countryCode": "US",
"number": "2179856987"
}
}
Field Reference
| Field | Type | Required | Validation | Purpose |
companyId | integer | Yes | positive int | Tenant ID. Determines available email domains. |
customerId | integer | Yes | positive int | Used as suffix in auto-generated USPTO email. |
nameTitle | string | No | max 50 | Salutation. Not used on USPTO form. |
firstName | string | Yes | 1–200 chars | Filled into USPTO "Create Account" first name field. |
middleName | string | No | max 200 | Filled into account form if present. |
lastName | string | Yes | 1–200 chars | Filled into USPTO account last name field. |
suffix | string | No | max 20 | Stored for records. Not on USPTO form. |
emailAddress | string | Yes | valid email | Your contact email. NOT the USPTO account email. |
isOldApplicant | boolean | No | default false | Set true to supply existing USPTO credentials directly and skip mailbox provisioning. Bot routes to Phase 2 immediately. |
emailDomain | string | Conditional | 1–250 chars | Required when isOldApplicant: false. Domain for auto-generated USPTO inbox. Must exist in AvailableDomains. Ignored when isOldApplicant: true. |
usptoAccountEmail | string | Conditional | valid email, max 500 | Required when isOldApplicant: true. The existing USPTO account email. Stored directly — no mailbox provisioned. |
usptoAccountPassword | string | Conditional | 1–500 chars | Required when isOldApplicant: true. The existing USPTO account password. Stored directly — no password generated. |
mfaSecret | string | Conditional | 1–500 chars | Required when isOldApplicant: true. The TOTP MFA secret (Base32). Used by the bot to generate 6-digit codes for login. |
country | string | Yes | 1–255 chars | ISO2 or full name. Used on USPTO account form. |
state | string | No | max 255 | ISO2 or full name. Only visible for US addresses. |
cityId | integer | No | positive int | City ID from lookup. Stored for records. |
streetAddress1 | string | Yes | 1–500 chars | Filled into USPTO account address field. |
streetAddress2 | string | No | max 500 | Additional address line. |
zipCode | string | No | max 50 | Filled into USPTO ZIP code field. |
pseudo | string | No | max 100 | Custom mailbox local-part prefix. When provided (non-empty), overrides the auto-generated {firstName}.{lastName} prefix. Final email: {pseudo}{customerId}@{domain}. Omit or set null to use the default. |
botCode | string | No | max 255 | Explicit bot assignment (e.g. "BOT_LIVE_1"). Bypasses the automatic least-loaded allocation policy. Invalid codes return 400. Omit or set null for auto-allocation. |
phone.dialCode | string | Yes | digits only, 1–15 | Country code. No + prefix. Bot auto-prepends it. |
phone.countryCode | string | No | max 10 | ISO2 phone country. Sets flag on form. |
phone.number | string | Yes | digits only, 5–15 | Raw digits. No dashes/spaces/parentheses. |
What Happens Internally
Mode A — New Applicant (isOldApplicant: false)
- Country/state codes resolved to database IDs.
emailDomain validated against AvailableDomains table.
- Duplicate check on
emailAddress and customerId + companyId. Returns existing record if found.
- Bot assigned via
botCode (explicit) or automatic least-loaded allocation policy.
- Cryptographically strong USPTO-compliant password auto-generated (14 chars).
- Applicant inserted with lifecycle
PENDING (1), email status PENDING.
- USPTO mailbox provisioned:
{pseudo}{customerId}@{emailDomain}. Lifecycle flipped to EMAIL_CREATED (2).
- Bot picks up on next cycle (every 10 seconds) and begins Phase 1 account creation.
Mode B — Old Applicant (isOldApplicant: true)
- Country/state codes resolved to database IDs.
- Duplicate check on
usptoAccountEmail, emailAddress, and customerId + companyId. Returns existing record if found.
- Bot assigned via
botCode (explicit) or automatic least-loaded allocation policy.
- Applicant inserted with provided credentials. Lifecycle set directly to
IDME_VERIFICATION_CLAIMED (13), email status CREATED. No password generation. No mailbox provisioning.
APPLICANT_STATUS_CHANGED callback fired immediately.
- Bot picks up on next cycle and begins Phase 2 (claim verification → filing) directly.
💡 Duplicate Behaviour (Both Modes)
If an applicant with the same
emailAddress,
usptoAccountEmail, or
customerId + companyId already exists, the API returns the existing record silently — no error, no duplicate insert. Check the returned
applicantId to detect this case.
Success Response — 201 Created
{
"IsSuccess": true,
"Data": {
"applicantId": 42,
"usptoAccountEmail": "[email protected]",
"usptoAccountPassword": "Tr@deMark#9821",
"emailProvisioned": true
},
"Message": "Applicant created successfully.",
"StatusCode": 201
}
GET /applicants/:id/get-2fa-code
Returns the current live 6-digit TOTP code for an applicant's USPTO MFA account.
The code is generated server-side from the MFASecret stored in the database using
RFC 6238 (SHA-1, 30-second window) — identical to Google Authenticator output.
GET
/api/v1/applicants/:id/get-2fa-code
URL Parameter
| Parameter | Type | Description |
id | integer | Applicant primary-key ID |
Success Response — 200 OK
{
"IsSuccess": true,
"Data": {
"applicantId": 24,
"usptoAccountEmail": "[email protected]",
"totpCode": "482910",
"generatedAt": "2026-06-06T00:00:00.000Z"
},
"Message": "Request completed successfully.",
"StatusCode": 200
}
Response Fields
| Field | Type | Description |
applicantId | integer | The applicant's database ID |
usptoAccountEmail | string | null | USPTO mailbox provisioned for this applicant |
totpCode | string (6 digits) | Current TOTP code. Valid for up to 30 seconds from generatedAt. |
generatedAt | ISO 8601 timestamp | UTC timestamp when the code was generated |
Error Responses
| HTTP | When |
404 | Applicant with given id does not exist or has been soft-deleted. |
409 | Applicant exists but MFASecret is not set — TOTP enrollment in Phase 1 has not completed yet. |
💡 Lifecycle Note
MFASecret is written to the database only after the bot completes the
TOTP enrollment step in
Phase 1 (Account Creation). If the applicant's
lifecycle status is below
ACCOUNT_CREATED (9), expect a
409 response.
PUT /applicants/:id/claim-idme-verified
Allows a tenant to report whether an applicant has completed ID.me identity verification.
Only applicants currently in ACCOUNT_CREATED (9) status are eligible.
PUT
/api/v1/applicants/:id/claim-idme-verified
URL Parameter
| Parameter | Type | Description |
id | integer | Applicant primary-key ID |
Query Parameters
| Parameter | Type | Default | Description |
isVerified | "true" | "false" | true | Whether the tenant reports ID.me as verified or failed. |
Behavior
| isVerified | New Status | What Happens Next |
true (default) |
IDME_VERIFICATION_CLAIMED (13) |
Bot picks up with high priority, signs in, navigates to /tm/verify-identity.
If confirmed → IDME_VERIFIED (11).
If not confirmed → reverts to ACCOUNT_CREATED (9) with an error message. |
false |
IDME_VERIF_FAILED (12) |
Terminal. Applicant is permanently marked as failed. No bot processing.
Fires APPLICANT_STATUS_CHANGED and IDME_VERIFICATION_FAILED callbacks. |
Success Response — 200 OK
// isVerified=true (default)
{
"IsSuccess": true,
"Data": {
"applicantId": 42,
"isVerified": true
},
"Message": "ID.me verification claim accepted. Bot will verify shortly.",
"StatusCode": 200
}
// isVerified=false
{
"IsSuccess": true,
"Data": {
"applicantId": 42,
"isVerified": false
},
"Message": "Applicant marked as ID.me verification failed (terminal).",
"StatusCode": 200
}
Error Responses
| HTTP | When |
400 | isVerified is present but not "true" or "false". |
404 | Applicant with given id does not exist or has been soft-deleted. |
409 | Applicant is not in ACCOUNT_CREATED (9) status. |
💡 Backward Compatibility
Omitting
?isVerified defaults to
true, so existing integrations that call this endpoint without the query parameter continue to work identically.
⚠️ isVerified=false is Terminal
Setting
isVerified=false is
irreversible. The applicant moves to status 12 (IDME_VERIFICATION_FAILED_WAITING_LIMIT_EXCEED) and will never be processed by the bot again. Only use this when you are certain ID.me verification has permanently failed.
GET /applicants/get-applicant-info
Returns a comprehensive snapshot of an applicant with full filing detail for all (or one specific) application. Includes resolved lookup titles, live TOTP code, and complete filing data (owners, attorney, correspondence, mark, goods/services, declaration).
GET
/api/v1/applicants/get-applicant-info
Query Parameters
| Parameter | Type | Required | Description |
applicantId | integer | Yes | The applicant's database ID. |
applicationId | integer | No | If provided, only returns detail for this specific application. If omitted, returns all applications. |
Response Shape
The response includes the full applicant profile at the top level, with an applications array containing detailed filing data for each application. All lookup IDs are resolved to { id, title } pairs.
| Field | Type | Description |
id | integer | Applicant database ID |
customerId | integer | null | Tenant-side customer reference |
nameTitle, firstName, middleName, lastName, suffix | string | null | Person name fields |
emailAddress | string | null | Contact email |
usptoAccountEmail | string | null | Provisioned USPTO mailbox |
usptoAccountPassword | string | null | USPTO account password |
mfaSecret | string | null | TOTP shared secret |
totpCode | string | null | Current live 6-digit TOTP code (null if MFA not enrolled) |
lastIdmeCheckedAt | ISO 8601 | null | Last ID.me verification attempt timestamp |
accountCreatedAt | ISO 8601 | null | When account was successfully created |
phone | object | { dialCode, countryCode, number } |
address | object | { streetAddress1, streetAddress2, zipCode, city, state, stateISO2, country } — city/state/country are { id, title } pairs |
lifeCycleStatus | { id, title } | Current lifecycle status |
emailStatus | { id, title } | Email provisioning status |
company | { id, title } | Tenant company |
applications | array | Full filing detail per application (see below) |
Each Application Object
| Field | Type | Description |
id | integer | Application database ID |
filingStatus | { id, title } | Current filing status |
applicationType | { id, title } | Application type (Standard, etc.) |
clientApplicationId | string | null | Your external reference ID |
owners | array | Full owner details with resolved entity types, addresses, members |
attorney | object | null | Attorney details (null if pro se) |
correspondence | object | null | Correspondence info with secondary emails |
mark | object | null | Mark details with resolved format/stylized types, translations, name consents |
goodsServices | array | Goods/services entries with resolved entry types, filing bases, foreign app/reg data |
declaration | object | null | Declaration with resolved signature method, all acknowledge flags |
Example Request
GET /api/v1/applicants/get-applicant-info?applicantId=42
GET /api/v1/applicants/get-applicant-info?applicantId=42&applicationId=101
Success Response — 200 OK (abbreviated)
{
"IsSuccess": true,
"Data": {
"id": 42,
"customerId": 1001,
"firstName": "Mike",
"lastName": "Jacob",
"emailAddress": "[email protected]",
"usptoAccountEmail": "[email protected]",
"usptoAccountPassword": "xY9!kP2m@LqR7n",
"mfaSecret": "JBSWY3DPEHPK3PXP",
"totpCode": "482910",
"accountCreatedAt": "2026-06-04T15:00:00.000Z",
"phone": { "dialCode": "1", "countryCode": "US", "number": "2179856987" },
"address": {
"streetAddress1": "411 Spruce St",
"city": { "id": 5, "title": "San Francisco" },
"state": { "id": 5, "title": "California" },
"stateISO2": "CA",
"country": { "id": 1, "title": "United States" }
},
"lifeCycleStatus": { "id": 11, "title": "IDME Verified" },
"emailStatus": { "id": 2, "title": "Created" },
"company": { "id": 5, "title": "TradeMark Luv" },
"applications": [
{
"id": 101,
"filingStatus": { "id": 3, "title": "Done" },
"applicationType": { "id": 1, "title": "Standard" },
"clientApplicationId": "CLIENT-REF-001",
"owners": [ { "ownerOrder": 1, "entityType": { "id": 1, "title": "Individual" }, ... } ],
"attorney": null,
"correspondence": { "name": "Mike Jacob", "primaryEmail": "[email protected]", ... },
"mark": { "format": { "id": 1, "title": "Standard Character Mark" }, "text": "NEXOCRAFT", ... },
"goodsServices": [ { "entryOrder": 1, "entryType": { "id": 1, "title": "ID Manual" }, ... } ],
"declaration": { "signatureMethod": { "id": 1, "title": "Electronic Signature" }, ... }
}
]
},
"Message": "Request completed successfully.",
"StatusCode": 200
}
Error Responses
| HTTP | When |
400 | applicantId is missing or not a valid number. applicationId is present but not a valid number. |
404 | Applicant not found. Or applicationId specified but does not belong to this applicant. |
💡 All lookups resolved
Every lookup ID (entity type, filing status, mark format, etc.) is returned as a
{ id, title } pair — your frontend never needs to call the lookup API separately.
POST /utility/create-uspto-email
Provisions a standalone USPTO-compatible email mailbox via the third-party email provider. This does not create an Applicant record — it is a pure utility for callers that need a mailbox outside the normal onboarding flow.
POST
/api/v1/utility/create-uspto-email
Request Body
{
"domain": "chattrik.com",
"name": "Munib Shaikh",
"email": "munib.shaikh"
}
Field Reference
| Field | Type | Required | Validation | Purpose |
domain | string | Yes | 1–250 chars | Domain for the mailbox (e.g. chattrik.com). |
name | string | Yes | 1–500 chars | Display name / pseudo for the mailbox. |
email | string | Yes | 1–500 chars, must NOT contain @ | Username part only. The full email will be email@domain. |
What Happens Internally
- Input validated via Zod —
email containing @ is rejected with 400.
- A cryptographically strong USPTO-compliant password is auto-generated (14 chars, mixed case + digits + special characters).
- Third-party email vendor API is called with
agent_Code = 0.
- Full email address (
email@domain) and password are returned.
Success Response — 201 Created
{
"IsSuccess": true,
"Data": {
"emailAddress": "[email protected]",
"password": "Xk7$mNp3Qw&jR2"
},
"Message": "Created",
"StatusCode": 201
}
Error Responses
| HTTP | When |
400 | Validation failed — missing field, email contains @, etc. |
502 | Third-party email provider returned an error. Response body includes vendorMessage. |
Error Response — 502 (vendor failure)
{
"IsSuccess": false,
"Data": {
"emailAddress": "[email protected]",
"vendorMessage": "Mailbox creation limit exceeded"
},
"Message": "USPTO mailbox provisioning failed at the email provider.",
"StatusCode": 502
}
💡 No Applicant Created
This endpoint only provisions a mailbox. If you need a full applicant with bot automation, use
POST /applicants/create-applicant instead.
POST /applications/create-complete-application
Creates a complete trademark filing in a single atomic transaction. All child entities are inserted together — if any part fails, nothing is saved.
POST
/api/v1/applications/create-complete-application
Top-Level Fields
| Field | Type | Required | Description |
applicantId | integer | Yes | Must reference an existing, non-deleted applicant (ideally IDME_VERIFIED). |
clientApplicationId | string | No | Your external reference ID. Stored but not used by the bot. |
application | object | Yes | { "typeCode": "standard" } |
owners | array | Yes | At least 1 owner. See Owner Object below. |
attorney | object | null | No | Set null to file pro se (without attorney). |
correspondence | object | Yes | Who receives USPTO communications. |
mark | object | Yes | The trademark itself. |
goodsServices | array | Yes | At least 1 entry. Each represents one Nice Classification class. |
declaration | object | Yes | Signatory declaration under penalty of perjury. |
Owner Object
| Field | Type | Required | Description | Purpose on USPTO Form |
ownerOrder | integer | Yes | Unique sequential order (1, 2, 3...). | Determines tab order on Owner page. |
entityTypeCode | string | Yes | See Lookup Values. | Controls which sub-form USPTO renders. |
firstName | string | Cond | Required for individual & sole_proprietorship. | Fills "First name" field. |
lastName | string | Cond | Required for individual & sole_proprietorship. | Fills "Last name" field. |
countryOfCitizenshipCode | string | Cond | Required for individual & sole_proprietorship. | Fills "Country of citizenship" dropdown. Must be filled first for individuals. |
entityName | string | Cond | Required for all non-individual types. | Fills "Owner name" for juristic entities. |
stateOfIncorporationCode | string | No | For US entities. | Fills "State where legally organized" dropdown. |
countryOfIncorporationCode | string | No | For foreign entities. | Fills "Country where legally organized" dropdown. |
domicile | Address | Yes | Principal place of business. | Fills Domicile Address section. |
sameDomicileAndMailing | boolean | Yes | If true, mailing = domicile. | Controls "same as mailing" checkbox. |
mailingAddress | Address | Cond | Required when sameDomicileAndMailing = false. | Fills Mailing Address section. |
email | string | Yes | Valid email address. | Fills owner email field. |
phone | Phone | No | Optional. If omitted, phone fields are left blank on the USPTO form. See Phone Object. | Fills phone + flag-picker. |
website | string | No | Owner's website URL. | Checks "add URL" checkbox, fills URL. |
isAddressPublic | boolean | No | Show domicile on public record. | Controls TSDR visibility. |
alternateName | string | No | DBA / alternate name. | Fills alternate name text field. |
alternateNameTypeCode | string | No | Required if alternateName set. | Selects type: DBA, AKA, TA. |
members | array | Cond | Required for: partnership, joint_venture, trust, estate. Optional for LLC types (USPTO form has no members section for LLCs). | Fills trustee/executor/partner cards. |
Address Object
| Field | Type | Required | Purpose |
streetLine1 | string | Yes | Fills "Address Line 1". |
streetLine2 | string | No | Fills "Address Line 2" (apt, suite). |
city | string | No | Fills "City" text field. |
state | string | No | Fills "State" dropdown. Only shown when country = "United States". |
postalCode | string | No | Fills "Zip/Postal Code". |
country | string | Yes | Fills "Country" dropdown. Drives State visibility. |
Phone Object
| Field | Type | Required | Purpose |
dialCode | string | Yes | Digits only, no +. Bot auto-prepends it. E.g. "1", "44". |
number | string | Yes | Digits only. Fills "Primary telephone" input. |
extension | string | No | Fills "Extension" input. |
Attorney Object
Set to null to file pro se (without attorney). The bot skips the Attorney page entirely.
| Field | Type | Required | Purpose |
name | string | Yes | Fills "Attorney name" field. |
firmName | string | No | Fills "Firm name" field. |
barStateCode | string | No | Fills "Bar membership state" dropdown. |
barNumber | string | No | Fills "Bar number" field. |
email | string | Yes | Attorney's email address. |
phone | Phone | Yes | Attorney's phone. |
address | Address | Yes | Attorney's mailing address. |
Correspondence Object
| Field | Type | Required | Purpose |
name | string | Yes | Fills "Correspondence Name". |
primaryEmail | string | Yes | Primary email for all USPTO communications. |
secondaryEmails | string[] | No | CC emails for correspondence. |
showPublicly | boolean | No | If true, email visible in TSDR. |
Mark Object
| Field | Type | Required | Purpose on USPTO Form |
formatCode | string | Yes | Selects mark format radio. Determines subsequent pages. |
text | string | Cond | Standard Character: fills text input. Special Form: fills "literal text" if detected. |
stylizedMarkTypeCode | string | Cond | Required for Special Form. Selects sub-type radio. |
colorClaimed | boolean | No | Drives Color Claimed page radio. |
description | string | Cond | Fallback for Mark Details. Bot first tries AI-generated description. |
colorClaim | string | No | Fallback for color claim textarea. |
disclaimer | string | No | Fills disclaimer on Additional Information page. |
drawingFile | FileRef | Cond | Required for Special Form. Uploaded to Mark Drawing page. |
soundFile | FileRef | Cond | Required for Sound Mark. |
motionFile | FileRef | Cond | Required for Motion Mark. |
translations | array | No | Each entry fills one translation row. Empty = "no foreign words". |
nameConsents | array | No | Each entry fills consent form. Empty = "no name/likeness". |
File Reference Object
Two options for providing files:
// Option A: Reference existing uploaded file
{ "fileAssetId": 123 }
// Option B: URL for bot to download
{ "sourceUrl": "https://example.com/logo.png" }
Mark Cross-Field Validation
| formatCode | text | drawingFile | soundFile | motionFile | stylizedMarkTypeCode | description |
Standard Character Mark | Required | Forbidden | — | — | — | — |
Special Form | — | Required | — | — | Required | Required |
Sound Mark | — | — | Required | — | — | — |
Motion Mark | — | — | — | Required | — | — |
Goods/Services Object
| Field | Type | Required | Purpose on USPTO Form |
entryOrder | integer | Yes | Order entries are added on the page. |
entryTypeCode | string | Yes | "idManual": search by subclass code. "freeForm": custom text. |
classNumber | string | Yes | 3-digit Nice class (e.g. "045", "009"). Zero-padded. |
subClassCode | string | Cond | Required for idManual. Search term on ID Manual tab. |
subClassTexts | string[] | No | Fills placeholder textareas in ID Manual entries. |
freeFormText | string | Cond | Required for freeForm. Typed into free-form textarea. |
filingBasisCode | string | Yes | Selects filing basis radio: 1A, 1B, 44D, 44E, 66A. |
firstUseAnywhereDate | string | Cond | MM/DD/YYYY. Required for 1A. "Date of first use anywhere". |
firstUseInCommerceDate | string | Cond | MM/DD/YYYY. Required for 1A. "Date of first use in commerce". |
specimen | object | Cond | Required for 1A. Proof of use (screenshot, label photo, etc.). |
foreignApplication | object | Cond | Required for 44D. Country, serial number, filing date. |
foreignRegistration | object | Cond | Required for 44E. Country, reg number, dates, certificate. |
Goods/Services Cross-Field Validation
| Basis | firstUseAnywhereDate | firstUseInCommerceDate | specimen | foreignApplication | foreignRegistration |
1A | Req | Req | Req | — | — |
1B | — | — | — | — | — |
44D | — | — | — | Req | — |
44E | — | — | — | — | Req |
66A | — | — | — | — | — |
Declaration Object
| Field | Type | Required | Purpose on USPTO Form |
signatureMethodCode | string | Yes | Selects signature method. Use "Electronic Signature". |
signatoryName | string | Yes | Fills "Signatory name". Declares under penalty of perjury. |
signatoryTitle | string | No | Fills "Signatory title" (e.g. CEO, Trustee). |
signatureText | string | Yes | E-signature: /FirstName LastName/ format. |
signatureDate | string | No | MM/DD/YYYY. USPTO auto-fills date — bot writes it back to DB. |
acknowledgeBasis | boolean | Yes | Must be true. "Entitled to use mark in commerce." |
acknowledgeUniqueness | boolean | Yes | Must be true. "No other person has right to use." |
acknowledgeFactualContents | boolean | Yes | Must be true. "All statements are true." |
acknowledgeWarning | boolean | Yes | Must be true. "Willful false statements punishable." |
⛔ All four acknowledge flags must be true
The request is rejected with
ACKNOWLEDGEMENT_REQUIRED if any flag is
false.
PUT /applications/create-complete-application/:appId
Atomically replaces an existing PENDING application. Deletes all child entities and re-inserts from the new payload.
PUT
/api/v1/applications/create-complete-application/{appId}
| Aspect | POST (Create) | PUT (Replace) |
| Creates new Application row | Yes | No — reuses existing |
| Deletes child entities first | No | Yes — atomic wipe + re-insert |
| Returns applicationId | New ID | Same appId from URL |
| Allowed status | Any | Application must exist & not be deleted |
| Response code | 201 | 200 |
Request body is identical to POST. The applicantId in the body is still required.
Lookup API Reference
GET
/api/v1/lookup/{resource}
| Resource | Description | Has Code Column |
owner-entity-types | All valid entity type codes | Yes |
filing-bases | Filing basis codes (1A, 1B, 44D, 44E, 66A) | Yes |
mark-formats | Mark format titles | No — use Title |
stylized-mark-types | Stylized mark sub-types | Yes |
goods-entry-types | idManual, freeForm | Yes |
signature-methods | Signature method titles | No — use Title |
name-likeness-types | Name, Portrait, Signature | Yes |
consent-proof-types | Declaration, Written Consent, Registration | Yes |
alternate-name-types | DBA, AKA, FKA, TA | Yes |
owner-member-roles | Member, Manager, Partner, Trustee, Executor, Beneficiary | Yes |
Other Lookup Endpoints
GET /api/v1/lookup/countries
GET /api/v1/lookup/states?countryId=1
GET /api/v1/lookup/cities?stateId=44
GET /api/v1/lookup/domains?companyId=1
GET /api/v1/lookup/companies
GET /api/v1/lookup/uspto-classes
GET /api/v1/lookup/uspto-sub-classes?classCode=045
All Lookup Values
📌 Note
All codes are
case-insensitive.
"us_llc",
"US_LLC",
"Us_Llc" all work.
Application Types
| Code | Title |
standard | Standard |
Owner Entity Types
| Code | Title | Required Fields |
individual | Individual | firstName, lastName, countryOfCitizenshipCode |
sole_proprietorship | Sole Proprietorship | entityName + firstName, lastName, countryOfCitizenshipCode |
us_corporation | US Corporation | entityName |
us_llc | US LLC | entityName |
foreign_corporation | Foreign Corporation | entityName |
foreign_llc | Foreign LLC | entityName |
partnership | Partnership | entityName, members[] |
limited_partnership | Limited Partnership | entityName, stateOfIncorporationCode |
joint_venture | Joint Venture | entityName, members[] |
trust | Trust | entityName, members[] |
estate | Estate | entityName, members[] |
government | Government | entityName |
other | Other | entityName |
Owner Member Roles
| Code | Title | Used With |
member | Member | us_llc, foreign_llc (optional — USPTO form has no members section for LLC) |
manager | Manager | us_llc, foreign_llc (optional) |
partner | Partner | partnership, joint_venture |
trustee | Trustee | trust |
executor | Executor | estate |
beneficiary | Beneficiary | trust, estate |
Alternate Name Types
| Code | Title |
dba | DBA (Doing Business As) |
aka | AKA (Also Known As) |
fka | FKA (Formerly Known As) |
ta | TA (Trading As) |
Mark Formats
⚠️ No Code column — pass the Title value
| Title (use as formatCode) | Description |
Standard Character Mark | Plain text only. No logo, no stylization. |
Special Form | Logo, stylized text, or design. Requires drawing file. |
Sound Mark | Audio mark. Requires sound file. |
Motion Mark | Video/animation mark. Requires motion file. |
Stylized Mark Types
| Code | Title |
design_only | Design Only |
wording_only | Wording Only |
wording_and_design | Wording and Design |
Filing Basis
| Code | Title | Trademark Act Section |
1A | Use in Commerce | §1(a) — Mark is already in use |
1B | Intent to Use | §1(b) — Bona fide intent to use |
44D | Foreign Application | §44(d) — Priority from foreign app |
44E | Foreign Registration | §44(e) — Based on foreign registration |
66A | Madrid Protocol | §66(a) — International registration |
Goods Entry Types
| Code | Title | Description |
idManual | ID Manual | Search by subclass code from USPTO's Trademark ID Manual. |
freeForm | Free Form | Custom description text (max 20,000 chars). |
Signature Methods
| Title (use as signatureMethodCode) |
Electronic Signature |
Handwritten Pen-and-Ink Signature |
Name Likeness Types
| Code | Title |
name | Name |
portrait | Portrait |
signature | Signature |
Consent Proof Types
| Code | Title |
declaration | Declaration |
written_consent | Written Consent |
registration | Registration |
Error Codes Reference
Schema Validation Errors (Zod — HTTP 400)
| Scenario | Example Error |
| Missing required field | "String must contain at least 1 character(s)" |
| Invalid email | "Invalid email" |
| Invalid date format | "Must be MM/DD/YYYY" |
| Invalid class number | "Must be 3-digit class like '045'" |
| Invalid phone.dialCode | "dialCode must contain digits only, no '+'" |
| Invalid phone.number | "number must contain digits only" |
Business Validation Errors (HTTP 400)
| Code | Path Example | When |
DUPLICATE_ORDER | owners[1].ownerOrder | Two owners have the same ownerOrder. |
REQUIRED | owners[0].firstName | Conditionally required field is missing. |
FORBIDDEN | owners[0].entityName | Field must be empty for this entity type. |
ACKNOWLEDGEMENT_REQUIRED | declaration | One or more acknowledge flags is false. |
UNKNOWN_CODE | owners[0].entityTypeCode | Lookup code doesn't exist in DB. |
UNKNOWN_FILE_ASSET | mark.drawingFile.fileAssetId | FileAsset doesn't exist or is deleted. |
UNKNOWN_DOMAIN | emailDomain | Domain not found in AvailableDomains. |
HTTP Status Codes
| Code | Meaning |
200 | Success (GET, PUT) |
201 | Created (POST) |
400 | Validation failed (schema or business rules) |
404 | Resource not found |
500 | Internal server error |
502 | Upstream dependency failure |
Complete Example Payloads
Example 1: Individual Owner, Standard Text Mark, 1A Basis
Scenario: An individual files a standard character trademark already in use.
{
"applicantId": 42,
"clientApplicationId": "CLIENT-REF-001",
"application": { "typeCode": "standard" },
"owners": [
{
"ownerOrder": 1,
"entityTypeCode": "individual",
"firstName": "Mike",
"lastName": "Jacob",
"countryOfCitizenshipCode": "US",
"domicile": {
"streetLine1": "411 Spruce St",
"city": "San Francisco",
"state": "CA",
"postalCode": "94102",
"country": "United States"
},
"sameDomicileAndMailing": true,
"noPhysicalLocation": false,
"email": "[email protected]",
"phone": { "dialCode": "1", "number": "2179856987" }
}
],
"attorney": null,
"correspondence": {
"name": "Mike Jacob",
"primaryEmail": "[email protected]"
},
"mark": {
"formatCode": "Standard Character Mark",
"text": "NEXOCRAFT",
"description": "The mark consists of standard characters NEXOCRAFT."
},
"goodsServices": [
{
"entryOrder": 1,
"entryTypeCode": "idManual",
"classNumber": "045",
"subClassCode": "045-2381",
"filingBasisCode": "1A",
"firstUseAnywhereDate": "01/15/2023",
"firstUseInCommerceDate": "03/01/2023",
"specimen": {
"description": "Screenshot of homepage showing the mark in use.",
"webUrl": "https://techbrand.com",
"accessDate": "2024-01-15",
"file": { "sourceUrl": "https://example.com/specimen.jpg" }
}
}
],
"declaration": {
"signatureMethodCode": "Electronic Signature",
"signatoryName": "Mike Jacob",
"signatureText": "/Mike Jacob/",
"acknowledgeBasis": true,
"acknowledgeUniqueness": true,
"acknowledgeFactualContents": true,
"acknowledgeWarning": true
}
}
Example 2: US LLC with Attorney, Logo Mark, Intent to Use
Scenario: A US LLC files a color logo with an attorney. members[] is included here for reference but is optional for LLC types — USPTO's form has no members section for LLCs.
{
"applicantId": 42,
"application": { "typeCode": "standard" },
"owners": [
{
"ownerOrder": 1,
"entityTypeCode": "us_llc",
"entityName": "TechBrand LLC",
"stateOfIncorporationCode": "DE",
"domicile": {
"streetLine1": "123 Innovation Drive",
"city": "Austin",
"state": "Texas",
"postalCode": "78701",
"country": "US"
},
"sameDomicileAndMailing": true,
"email": "[email protected]",
"phone": { "dialCode": "1", "number": "5125550101" },
"website": "https://techbrand.com",
"members": [
{ "roleCode": "member", "name": "John Carter", "entityType": "individual", "countryCode": "US" },
{ "roleCode": "manager", "name": "Jane Doe", "entityType": "individual", "countryCode": "US" }
]
}
],
"attorney": {
"name": "Jane Smith",
"firmName": "Smith IP Law PLLC",
"barStateCode": "TX",
"barNumber": "TX-24098765",
"email": "[email protected]",
"phone": { "dialCode": "1", "number": "5125559988" },
"address": {
"streetLine1": "500 Congress Ave",
"city": "Austin",
"state": "TX",
"postalCode": "78701",
"country": "US"
}
},
"correspondence": {
"name": "Jane Smith",
"primaryEmail": "[email protected]",
"secondaryEmails": ["[email protected]"]
},
"mark": {
"formatCode": "Special Form",
"text": "TECHBRAND",
"stylizedMarkTypeCode": "Wording and Design",
"colorClaimed": true,
"description": "The mark consists of TECHBRAND in stylized blue text with a gear icon.",
"colorClaim": "The color blue is claimed as a feature of the mark.",
"drawingFile": { "sourceUrl": "https://example.com/logo.png" }
},
"goodsServices": [
{
"entryOrder": 1,
"entryTypeCode": "freeForm",
"classNumber": "042",
"freeFormText": "Software as a service (SaaS) featuring platforms for business automation",
"filingBasisCode": "1B"
}
],
"declaration": {
"signatureMethodCode": "Electronic Signature",
"signatoryName": "John Carter",
"signatoryTitle": "CEO",
"signatureText": "/John Carter/",
"acknowledgeBasis": true,
"acknowledgeUniqueness": true,
"acknowledgeFactualContents": true,
"acknowledgeWarning": true
}
}
Example 3: Trust with Translations & Name Consent
Scenario: A trust with trustees files a color logo containing a foreign word and a living person's name.
{
"applicantId": 42,
"application": { "typeCode": "standard" },
"owners": [
{
"ownerOrder": 1,
"entityTypeCode": "trust",
"entityName": "Carter Family Trust",
"domicile": {
"streetLine1": "500 Park Ave",
"city": "New York",
"state": "NY",
"postalCode": "10022",
"country": "United States"
},
"sameDomicileAndMailing": false,
"mailingAddress": {
"streetLine1": "PO Box 5500",
"city": "New York",
"state": "NY",
"postalCode": "10022",
"country": "US"
},
"email": "[email protected]",
"phone": { "dialCode": "1", "number": "2125550300" },
"members": [
{ "roleCode": "trustee", "name": "John Carter", "entityType": "individual", "countryCode": "US" },
{ "roleCode": "trustee", "name": "Sarah Carter", "entityType": "individual", "countryCode": "US" }
]
}
],
"attorney": null,
"correspondence": {
"name": "John Carter",
"primaryEmail": "[email protected]"
},
"mark": {
"formatCode": "Special Form",
"text": "CASA CARTER",
"stylizedMarkTypeCode": "Wording and Design",
"colorClaimed": true,
"description": "The mark consists of CASA CARTER in stylized gold script over a shield design.",
"colorClaim": "The colors gold and navy blue are claimed as features of the mark.",
"drawingFile": { "sourceUrl": "https://example.com/casa-carter-logo.png" },
"translations": [
{
"isNonLatinPhrase": false,
"nonEnglishWord": "Casa",
"language": "Spanish",
"hasEnglishMeaning": true,
"englishTranslation": "House"
}
],
"nameConsents": [
{
"likenessTypeCode": "name",
"legalName": "John Carter",
"isSignatory": true,
"consentToRegister": true,
"proofTypeCode": "declaration"
}
]
},
"goodsServices": [
{
"entryOrder": 1,
"entryTypeCode": "idManual",
"classNumber": "025",
"subClassCode": "025-0100",
"filingBasisCode": "1B"
}
],
"declaration": {
"signatureMethodCode": "Electronic Signature",
"signatoryName": "John Carter",
"signatoryTitle": "Trustee",
"signatureText": "/John Carter/",
"acknowledgeBasis": true,
"acknowledgeUniqueness": true,
"acknowledgeFactualContents": true,
"acknowledgeWarning": true
}
}
Fetching USPTO Classes
GET /api/v1/lookup/uspto-classes
→ [
{ "Id": 1, "ClassCode": "001", "ClassTitle": "Chemicals", "ClassType": "Goods" },
{ "Id": 9, "ClassCode": "009", "ClassTitle": "Electrical and Scientific Apparatus", "ClassType": "Goods" },
{ "Id": 42, "ClassCode": "042", "ClassTitle": "Computer & Scientific & Legal", "ClassType": "Services" },
{ "Id": 45, "ClassCode": "045", "ClassTitle": "Personal & Legal & Social", "ClassType": "Services" }
]
GET /api/v1/lookup/uspto-sub-classes?classCode=045
→ [
{ "Id": 100, "SubClassCode": "045-2381", "ClassCode": "045", "SubClassTitle": "Online social networking..." },
{ "Id": 101, "SubClassCode": "045-2380", "ClassCode": "045", "SubClassTitle": "Social introduction..." }
]
Date Format Summary
| Context | Format | Example |
firstUseAnywhereDate | MM/DD/YYYY | "01/15/2023" |
firstUseInCommerceDate | MM/DD/YYYY | "03/01/2023" |
signatureDate | MM/DD/YYYY | "06/03/2026" |
foreignApplication.filingDate | YYYY-MM-DD | "2023-06-15" |
foreignRegistration.registrationDate | YYYY-MM-DD | "2023-09-01" |
foreignRegistration.expirationDate | YYYY-MM-DD | "2033-09-01" |
specimen.accessDate | YYYY-MM-DD | "2024-01-15" |
📅 Date Format Rule
Domestic dates use
MM/DD/YYYY (USPTO format). Foreign dates use
YYYY-MM-DD (ISO).
Bot Automation Details
Filing Data Pipeline
Your API Call (POST /create-complete-application)
│
▼
┌─────────────────────────────────────────────────┐
│ 1. Zod Schema Validation │
│ → masterFilingSchema validates structure │
│ → Cross-field rules (entity type, basis, etc.)│
├─────────────────────────────────────────────────┤
│ 2. Business Validation │
│ → Resolve all codes to DB IDs │
│ → Validate file assets exist │
│ → Check acknowledgement flags │
├─────────────────────────────────────────────────┤
│ 3. MSSQL Transaction (atomic insert) │
│ → Application + Owners + Attorney + │
│ Correspondence + Mark + Goods + Declaration │
├─────────────────────────────────────────────────┤
│ 4. Filing Status = PENDING │
│ → Queued for bot pickup │
└─────────────────────────────────────────────────┘
│ (bot picks up on next cycle — every 10s)
▼
┌─────────────────────────────────────────────────┐
│ 5. Filing Data Assembly │
│ → DB → IRawFilingPayload → IFilingFormData │
├─────────────────────────────────────────────────┤
│ 6. USPTO Wizard Automation │
│ → Signs in with stored credentials + TOTP │
│ → Navigates wizard (max 50 page visits) │
│ → Fills each page declaratively │
├─────────────────────────────────────────────────┤
│ 7. Outcome │
│ → Success: Status = DONE + webhook │
│ → Error: Status = ERROR + webhook │
└─────────────────────────────────────────────────┘
Bot Behavior Highlights
- Draft, not submit: The bot saves as a USPTO draft — does NOT click final "Submit".
- Signature date writeback: USPTO auto-generates a signing date. Bot reads it and writes back to your DB.
- AI mark description: For Special Form, bot accepts USPTO's AI suggestion. Falls back to your text if AI fails.
- Color conversion: Color image +
colorClaimed = false → bot auto-accepts B&W conversion.
- Multi-owner tabs: Bot adds owner tabs via "+ Add" and fills each sequentially.
- Phone dial code: Bot interacts with flag-picker. US default (
"1") needs no interaction.
- Screenshots: Taken at key steps and on every error. Stored in
screenshots/.
- Error reporting: Page validation errors captured and sent via webhook.
Webhook Callbacks
| Event | When |
EMAIL_PROVISIONED | USPTO mailbox provisioned successfully. |
APPLICANT_STATUS_CHANGED | Any lifecycle status transition. |
ACCOUNT_FAILED | Account creation failed (terminal). |
IDME_VERIFIED | ID.me verification completed — ready for filing. |
IDME_VERIFICATION_FAILED | ID.me wait limit exceeded (bot) or tenant reported failure (API). |
FILING_STATUS_CHANGED | Filing status changes (PENDING → UNDER_PROCESS → DONE/ERROR). |
SUBMISSION_COMPLETED | Filing saved as draft successfully. |
SUBMISSION_FAILED | Filing failed with error. |
Callbacks are delivered with retry logic (configurable per company). Failed deliveries use linear backoff up to a configurable maximum.
WebSocket — Live TOTP Authenticator
The server exposes a WebSocket endpoint that pushes the current live TOTP codes
for all enrolled applicants every 10 seconds (configurable via
AUTHENTICATOR_REFRESH_INTERVAL_MS env var). No polling required — just connect and listen.
WS
/api/authenticator
Connect & Listen
const ws = new WebSocket("https://filingbot.crmbytes.com/api/authenticator");
ws.onopen = () => console.log("Connected");
ws.onmessage = (e) => {
const snapshot = JSON.parse(e.data);
console.log(snapshot);
};
ws.onclose = () => console.log("Disconnected");
ws.onerror = (err) => console.error("WS error", err);
Behavior on Connect
⚡ Immediate First Message
Upon connecting, the server
immediately sends the last known snapshot
so the client doesn’t have to wait up to 10 seconds for the first broadcast.
After that, a fresh snapshot is pushed every
AUTHENTICATOR_REFRESH_INTERVAL_MS (default 10s).
Message Shape (IAuthenticatorSnapshot)
{
"capturedAt": "2026-06-06T00:00:00.000Z",
"entries": [
{
"issuer": "[email protected]",
"account": "Applicant #24",
"code": "482910"
},
{
"issuer": "[email protected]",
"account": "Applicant #42",
"code": "719034"
}
]
}
Field Reference
| Field | Type | Description |
capturedAt | ISO 8601 string | UTC timestamp when this snapshot was generated |
entries | array | One entry per enrolled applicant. Empty array if no applicants have an MFASecret yet. |
entries[].issuer | string | The applicant’s USPTO account email (USPTOAccountEmail) |
entries[].account | string | Human-readable label e.g. "Applicant #24" |
entries[].code | string (6 digits) | Current live TOTP code. Valid for the remainder of the current 30-second window. |
Key Points
- Server-sent only — this is a one-way broadcast. The client never sends messages; the server ignores any inbound frames.
- All applicants in one message — every broadcast contains codes for all enrolled applicants. Filter by
issuer or account on the client side.
- Same port — no extra port. The WS server is attached to the same HTTP server as the REST API (
:3001 by default).
- Codes expire every 30s — RFC 6238, SHA-1, 30-second window. A code received near a window boundary may expire within seconds. The next broadcast (within 10s) will carry the fresh code.
- Only enrolled applicants — applicants without an
MFASecret (Phase 1 not yet completed) are silently excluded from the snapshot.