Brokerage Firms
A brokerage firm is a benefits broker that services one or more of your Organizations. The Broker-of-Record relationship is with the firm, not with its individual brokers. Use the Partner API to register a firm, assign your Organizations to it, add its brokers, and remove Organizations from it.
Concepts
| Concept | Definition |
|---|---|
| Brokerage firm | A broker business, identified by its EIN. First Dollar keeps one registry of firms for all partners, so the firm you register can already exist. |
| Broker | A person who works for a brokerage firm and signs in to First Dollar with their own identity. |
| Firm admin | A broker who administers the firm. createBrokerageFirm creates the first firm admin. addBrokerToFirm with isFirmAdmin: true adds more. |
| Organization assignment | A link between a firm and one of your Organizations. The firm services each Organization that is assigned to it, and removing the assignment revokes the firm's access to it. |
Before you start:
- The firm registry is shared across partners. Firms are deduplicated on EIN. A firm's name, EIN and
idare not confidential, and another partner can have registered the firm you look up. - A firm's brokers service every Organization that is assigned to the firm, whichever partner assigned it. Confirm that a firm is the right one before you assign an Organization to it.
- You change only your own Organizations. You can assign and remove only Organizations that you control. Your requests never change another partner's assignments to the same firm.
- Identify each Organization by its
id. Pass the Organization'sidinorganizationUlids. Organization short codes are not accepted. - Save each firm's
id. The Partner API has no query for brokerage firms.createBrokerageFirmreturns the firm, and the other operations take itsid. If you lose a firm'sid, callcreateBrokerageFirmagain with the same EIN and noorganizationUlids: the existing firm is returned asALREADY_EXISTEDand nothing about it changes. ThefirmAdmininput is required but ignored for an existing firm. Check the EIN first, because an EIN that matches no firm creates a new one.
Register a brokerage firm
Call createBrokerageFirm with the firm's EIN, its name, its first firm admin and, optionally, the Organizations that it services.
mutation CreateBrokerageFirm($input: CreateBrokerageFirmInput!) {
createBrokerageFirm(input: $input) {
... on CreateBrokerageFirmResult {
status
matchedBy
firmAdminUid
firm {
id
ein
einIsPlaceholder
name
inactiveAt
}
organizationAssignments {
organizationUlid
status
reason
}
}
... on BadRequestError {
code
message
}
... on InternalServerError {
code
message
}
}
}
Variables:
{
"input": {
"ein": "12-3456789",
"name": "Acme Benefits LLC",
"firmAdmin": {
"firstName": "Jordan",
"lastName": "Lee"
},
"organizationUlids": ["<organizationId>"]
}
}
The EIN can be punctuated (12-3456789) or bare (123456789). Both identify the same firm.
Read the result
Use status and matchedBy to find out what happened:
status | matchedBy | What happened | What to do next |
|---|---|---|---|
CREATED | null | The firm and its first firm admin were created. firmAdminUid identifies the firm admin. The Organizations that you named are assigned to the firm. | Save firm.id. |
ALREADY_EXISTED | EIN | A firm with this EIN already exists. It is returned unchanged, and no firm admin is created (firmAdminUid is null). The Organizations that you named are assigned to it. | Save firm.id. To add your contacts at the firm, use Add a broker to a firm. |
ALREADY_EXISTED | NAME | The request had no EIN, and the firm's name matched one existing firm. Nothing is assigned, and no firm admin is created. | Have a person confirm that this is the right firm. Then assign your Organizations with assignOrganizationsToFirm. Do not repeat the request automatically. |
If firm.inactiveAt has a value, the firm is deactivated. Reactivating a firm is a manual step: contact [email protected].
Organizations named at registration
organizationUlids is all-or-nothing on createBrokerageFirm. If one identifier is not a valid ULID, or is not an Organization that you control, the call returns BadRequestError and no firm is created. A maximum of 250 Organizations is accepted per request.
When the firm is created or matched by EIN, organizationAssignments has one element for each identifier that you sent, in the same order. Expect each element to be CREATED or ALREADY_ASSIGNED. Read status on every element all the same: in rare cases an element is FAILED, and you recover it with assignOrganizationsToFirm.
If you named Organizations and organizationAssignments is null:
- With
matchedBy: NAME, this is expected. Nothing is assigned until a person confirms the match. - With
status: CREATEDormatchedBy: EIN, the firm and its firm admin exist, but the assignment did not complete. Call assignOrganizationsToFirm withfirm.id. It is idempotent, so it is safe to repeat.
Firms without an EIN
For a limited period, ein is optional. Send it whenever you have it. When you leave it out, First Dollar matches the firm on its normalized name: lowercase, punctuation removed, and runs of spaces collapsed to one. Business suffixes are kept, so Acme Benefits and Acme Benefits LLC are different names.
- One firm has the name. It is returned as
ALREADY_EXISTEDwithmatchedBy: NAME, and nothing is assigned. - No firm has the name. The firm is created with a placeholder EIN:
18-followed by seven digits.einIsPlaceholderistrue. A placeholder identifies the firm but is not a tax identifier. - More than one firm has the name. The call returns
BadRequestErrorand asks for the EIN. Nothing is written.
An empty ein is rejected, not treated as missing. An EIN that starts with 18 is also rejected, because that prefix is reserved for placeholders.
Errors
createBrokerageFirm returns BadRequestError with one of these codes:
code | Meaning |
|---|---|
FIRM_INACTIVE | The EIN (or, without an EIN, the name) matched a deactivated firm, and you named Organizations. Reactivating a firm is a manual step. |
NOT_FOUND | The EIN matched a firm outside your authority, and you named Organizations. |
BAD_REQUEST | The request is not valid. For example: a malformed EIN, more than 250 Organizations, an Organization that you do not control, a name that matches more than one firm, a firm admin email that already belongs to a First Dollar user, or a caller that is not permitted to register firms. |
FIRM_INACTIVE and NOT_FOUND occur only when organizationUlids is not empty. Without Organizations, an existing firm is always returned as ALREADY_EXISTED.
Assign Organizations to a firm
Call assignOrganizationsToFirm to have a firm service more of your Organizations. The firm can be one that you registered or one that another partner registered.
mutation AssignOrganizationsToFirm($input: AssignOrganizationsToFirmInput!) {
assignOrganizationsToFirm(input: $input) {
... on AssignOrganizationsToFirmResult {
organizationAssignments {
organizationUlid
status
reason
}
}
... on BadRequestError {
code
message
}
... on InternalServerError {
code
message
}
}
}
Variables:
{
"input": {
"firmId": "<firm.id>",
"organizationUlids": ["<organizationId>", "<organizationId>"]
}
}
The operation is idempotent and partially successful. Each identifier that you send gets its own element in organizationAssignments, in the same order, and organizationUlid echoes the value that you sent. One identifier that fails does not affect the others. A response in which every element failed is still an AssignOrganizationsToFirmResult, so read status on each element.
status | Meaning |
|---|---|
CREATED | The Organization is now assigned. This includes an assignment that was removed and is restored. |
ALREADY_ASSIGNED | The Organization was already assigned. Nothing changed. |
FAILED | The Organization was not assigned. reason tells you why. |
reason is set only for FAILED:
ORGANIZATION_ULID_MALFORMED: the value is not a valid ULID.ORGANIZATION_NOT_FOUND_OR_NOT_PERMITTED: the Organization does not exist, belongs to another partner, or is otherwise not one that you control. These cases are deliberately indistinguishable.
Send a maximum of 250 Organizations per request. Duplicate identifiers are written once but get one element each.
The request fails as a whole with BadRequestError when:
code | Meaning |
|---|---|
FORBIDDEN | You are not permitted to perform this operation. |
NOT_FOUND | No firm has this firmId. |
FIRM_INACTIVE | The firm is deactivated. Reactivating a firm is a manual step. |
BAD_REQUEST | The request is not valid. For example, it names more than 250 Organizations. |
Add a broker to a firm
Call addBrokerToFirm to give a person at the firm their own broker identity. Set isFirmAdmin to true to make the broker a firm admin.
The firm must be active and must have at least one of your Organizations assigned to it. Otherwise the call returns BadRequestError with code NOT_FOUND. The same response covers a firm that does not exist, is deactivated, or has none of your Organizations assigned to it.
mutation AddBrokerToFirm($input: AddBrokerToFirmInput!) {
addBrokerToFirm(input: $input) {
... on AddBrokerToFirmResult {
brokerageFirmUlid
status
brokerUid
inviteStatus
}
... on BadRequestError {
code
message
}
... on InternalServerError {
code
message
}
}
}
Variables:
{
"input": {
"brokerageFirmUlid": "<firm.id>",
"firstName": "Sam",
"lastName": "Rivera",
"isFirmAdmin": false
}
}
brokerageFirmUlid is the firm's id.
status | Meaning | What to do next |
|---|---|---|
CREATED | The broker's identity and firm membership were created. brokerUid identifies the broker. | Check inviteStatus. |
ALREADY_ACTIVE_MEMBER | The email already belongs to an active broker of this firm. brokerUid identifies the broker. | Nothing, unless you want to send the invitation again (see below). |
EMAIL_ALREADY_EXISTS | The email belongs to an existing First Dollar user who cannot be added to this firm. | Use a different email address for the broker. |
INACTIVE_MEMBERSHIP | The email belongs to a deactivated broker of this firm. The broker is not reactivated automatically. | Contact developer support. |
inviteStatus tells you what happened to the broker's invitation:
inviteStatus | Meaning |
|---|---|
SENT | First Dollar sent the invitation. This does not confirm that the email was delivered. |
FAILED | The broker was created, but the invitation could not be sent. |
SKIPPED | Broker invitations are not enabled for your partner. Contact developer support to enable them. |
null | No invitation was attempted, for example because the status is EMAIL_ALREADY_EXISTS. |
To send an invitation again, call addBrokerToFirm again with the same email. Until the broker signs in for the first time, the call returns ALREADY_ACTIVE_MEMBER and tries the invitation again. After the first sign-in, inviteStatus is null.
The request fails as a whole with BadRequestError when:
code | Meaning |
|---|---|
FORBIDDEN | You are not permitted to perform this operation. |
NOT_FOUND | The firm does not exist, is deactivated, or has none of your Organizations assigned to it. |
BAD_REQUEST | The request is not valid. For example, a required field is empty or a value is not in a valid format. |
Remove Organizations from a firm
Call unassignOrganizationsFromFirm when a firm no longer services some of your Organizations. The firm's access to those Organizations is revoked.
mutation UnassignOrganizationsFromFirm($input: UnassignOrganizationsFromFirmInput!) {
unassignOrganizationsFromFirm(input: $input) {
... on UnassignOrganizationsFromFirmResult {
organizationUnassignments {
organizationUlid
status
reason
}
}
... on BadRequestError {
code
message
}
... on InternalServerError {
code
message
}
}
}
Variables:
{
"input": {
"firmId": "<firm.id>",
"organizationUlids": ["<organizationId>"]
}
}
Removal changes only what you name:
- It affects only your own Organizations, never another partner's assignments to the same firm.
- It does not deactivate the firm or its brokers. The brokers keep their identities and every other Organization that they service.
- It works on a deactivated firm, so revoking access is never blocked by the state of the firm.
The operation is idempotent and partially successful, on the same terms as assignOrganizationsToFirm. Read status on each element:
status | Meaning |
|---|---|
REMOVED | The assignment was found and removed. |
ALREADY_UNASSIGNED | There was no active assignment, because it was already removed or was never made. |
FAILED | The Organization was not removed. reason has the same values as for assignment. |
The request fails as a whole with BadRequestError when:
code | Meaning |
|---|---|
FORBIDDEN | You are not permitted to perform this operation. |
NOT_FOUND | The firm does not exist, or it is not a firm that you work with. |
BAD_REQUEST | The request is not valid. For example, it names more than 250 Organizations. |
Retries
Every operation on this page returns InternalServerError for an unexpected failure. You can repeat each of them safely:
assignOrganizationsToFirmandunassignOrganizationsFromFirmare idempotent.createBrokerageFirmwith an EIN returns the existing firm asALREADY_EXISTEDif the first call created it.addBrokerToFirmreturnsALREADY_ACTIVE_MEMBERif the first call created the broker.
Related
- Organizations: create and manage the Organizations that you assign to firms.
- Organization Hierarchy: how Organization Groups, Organizations and Divisions relate.