Skip to main content

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​

ConceptDefinition
Brokerage firmA broker business, identified by its EIN. First Dollar keeps one registry of firms for all partners, so the firm you register can already exist.
BrokerA person who works for a brokerage firm and signs in to First Dollar with their own identity.
Firm adminA broker who administers the firm. createBrokerageFirm creates the first firm admin. addBrokerToFirm with isFirmAdmin: true adds more.
Organization assignmentA 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 id are 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's id in organizationUlids. Organization short codes are not accepted.
  • Save each firm's id. The Partner API has no query for brokerage firms. createBrokerageFirm returns the firm, and the other operations take its id. If you lose a firm's id, call createBrokerageFirm again with the same EIN and no organizationUlids: the existing firm is returned as ALREADY_EXISTED and nothing about it changes. The firmAdmin input 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": {
"email": "[email protected]",
"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:

statusmatchedByWhat happenedWhat to do next
CREATEDnullThe 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_EXISTEDEINA 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_EXISTEDNAMEThe 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: CREATED or matchedBy: EIN, the firm and its firm admin exist, but the assignment did not complete. Call assignOrganizationsToFirm with firm.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_EXISTED with matchedBy: NAME, and nothing is assigned.
  • No firm has the name. The firm is created with a placeholder EIN: 18- followed by seven digits. einIsPlaceholder is true. A placeholder identifies the firm but is not a tax identifier.
  • More than one firm has the name. The call returns BadRequestError and 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:

codeMeaning
FIRM_INACTIVEThe EIN (or, without an EIN, the name) matched a deactivated firm, and you named Organizations. Reactivating a firm is a manual step.
NOT_FOUNDThe EIN matched a firm outside your authority, and you named Organizations.
BAD_REQUESTThe 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.

statusMeaning
CREATEDThe Organization is now assigned. This includes an assignment that was removed and is restored.
ALREADY_ASSIGNEDThe Organization was already assigned. Nothing changed.
FAILEDThe 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:

codeMeaning
FORBIDDENYou are not permitted to perform this operation.
NOT_FOUNDNo firm has this firmId.
FIRM_INACTIVEThe firm is deactivated. Reactivating a firm is a manual step.
BAD_REQUESTThe 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>",
"email": "[email protected]",
"firstName": "Sam",
"lastName": "Rivera",
"isFirmAdmin": false
}
}

brokerageFirmUlid is the firm's id.

statusMeaningWhat to do next
CREATEDThe broker's identity and firm membership were created. brokerUid identifies the broker.Check inviteStatus.
ALREADY_ACTIVE_MEMBERThe 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_EXISTSThe email belongs to an existing First Dollar user who cannot be added to this firm.Use a different email address for the broker.
INACTIVE_MEMBERSHIPThe 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:

inviteStatusMeaning
SENTFirst Dollar sent the invitation. This does not confirm that the email was delivered.
FAILEDThe broker was created, but the invitation could not be sent.
SKIPPEDBroker invitations are not enabled for your partner. Contact developer support to enable them.
nullNo 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:

codeMeaning
FORBIDDENYou are not permitted to perform this operation.
NOT_FOUNDThe firm does not exist, is deactivated, or has none of your Organizations assigned to it.
BAD_REQUESTThe 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:

statusMeaning
REMOVEDThe assignment was found and removed.
ALREADY_UNASSIGNEDThere was no active assignment, because it was already removed or was never made.
FAILEDThe Organization was not removed. reason has the same values as for assignment.

The request fails as a whole with BadRequestError when:

codeMeaning
FORBIDDENYou are not permitted to perform this operation.
NOT_FOUNDThe firm does not exist, or it is not a firm that you work with.
BAD_REQUESTThe 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:

  • assignOrganizationsToFirm and unassignOrganizationsFromFirm are idempotent.
  • createBrokerageFirm with an EIN returns the existing firm as ALREADY_EXISTED if the first call created it.
  • addBrokerToFirm returns ALREADY_ACTIVE_MEMBER if the first call created the broker.