## About

Your organization has two options for Bring Your Own Token:

- **Processor Tokens Only** — A processor token is provided from a supported connector (e.g. a Plaid processor token) alongside each email. Users enroll by entering their email and personal information in Bloom+. The processor token is used to automatically link their bank account.
- **Invite Tokens** — A processor token is provided from a supported connector (e.g. a Plaid processor token) alongside each email. Bloom generates a short code (like `ABCD-EFGH-IJKL`) for each entry. You send the code to users. Users enroll by entering their email, invite code, and personal information in Bloom+. The processor token is used to automatically link their bank account.

The BYOT Process:

1. Receive Organization environment credentials for BYOT.
2. Authenticate into your Organization's environment.
3. Call the Bloom API's endpoint to register your users. You create invite tokens in batches (up to 500 at a time) using this endpoint.
4. Inform your users of their ability to register, either with an invite code or without.

---

## To Begin

You need two things before you can use this endpoint:

### 1. Your Organization ID (`x-partner`)

This is a UUID that identifies your organization. For example:

```undefined
a1b2c3d4-e5f6-7890-abcd-ef1234567890
```

If you don't have your organization ID, reach out to your Bloom representative.

### 2. Know your Organization's Mode

Your organization is configured in one of two modes. The mode determines what you send in your requests and what you get back:

| Mode | Request Body | Response Body |
| --- | --- | --- |
| **Processor Tokens Only** | Emails + processor tokens | Confirmation of each token |
| **Invite Tokens** | Emails + processor tokens | An invite code per email |

---

## BYOT Workflow

### Base URL

Use the following base URL depending on your environment:

| Environment | Base URL |
| --- | --- |
| Sandbox | `https://api.bloomplus.dev` |
| Production | `https://api.bloomplus.com` |

Sandbox processor tokens (e.g. `processor-sandbox-...`) must be used with the sandbox base URL. Production processor tokens must be used with the production base URL.

### Authentication

This endpoint uses an organization access token passed as a bearer token in the `Authorization` header.

### Headers

| Header | Value | Description |
| --- | --- | --- |
| `x-partner` | Your organization UUID | Identifies your organization. Required. |
| `Content-Type` | `application/json` | Always `application/json`. Required. |

If `x-partner` is missing, invalid, or doesn't match a known organization, you will get a `401 Unauthorized` error.

### Endpoint

```undefined
POST https://api.bloomplus.dev/v2/invite-tokens
```

### Request body

Example (detailed examples in [Behavior By Mode](https://developers.bloomcredit.io/docs/bring-your-own-token#behavior-by-mode)):

JSON

```json
{
  "expiration_days": 30,
  "tokens": [
    {
      "email": "user1@example.com",
      "processor_tokens": ["proc-token-abc123"]
    },
    {
      "email": "user2@example.com",
      "processor_tokens": ["proc-token-abc456", "proc-token-abc789"]
    }
  ]
}
```

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `expiration_days` | integer | No | Days until the token expires. Min: 1, Max: 365. **Default: 7.** Once expired, the invite code can no longer be used for enrollment and cannot be renewed. Reissue a new token for that email if needed. |
| `tokens` | array | Yes | List of tokens to create. Min: 1, Max: 500 per request. |

Each item in the `tokens` array:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `email` | string | Yes | The user's email address. Max 254 characters. |
| `processor_tokens` | string | Yes | A list of tokens from your financial institution (e.g. Plaid processor token). Max 255 characters each. Max 25 per email. |

### Important rules

- **Emails are NOT case sensitive.** `User@Example.com` and `user@example.com` are treated as the same email.
- **Whitespace is trimmed automatically.** Leading and trailing spaces on emails and processor tokens are stripped before processing.
- **No duplicate emails.** Each email can only appear once in a single request.
- **Duplicate processor tokens are deduped.** If the same processor token appears more than once under a single email, duplicates are silently removed. The same token cannot appear across different emails in the same request.
- **One active invite token per email per organization.** If an invite token already exists for an email that hasn't expired yet, creating another will fail with a conflict error.
- **Processor tokens are globally unique.** A processor token can only be used once, even across different organizations.

---

## Behavior by Mode

### Mode 1: Processor Tokens Only

You send an email and a processor token for each user. Users do not receive an invite code. Once registered via the API, users enter their email in Bloom+ to begin enrollment. Their bank account is automatically linked via the processor token.

A processor token is obtained from a supported financial connector. It gives Bloom permission to access the user's bank account data during onboarding. These examples use a Plaid processor token. See [Plaid's documentation](https://plaid.com/docs/api/processors/) for how to generate processor tokens. The process is the same when used in the context of Bloom invite tokens.

**Request:**

JSON

```json
{
  "expiration_days": 30,
  "tokens": [
    { "email": "alice@example.com", "processor_tokens": ["processor-sandbox-abc123"] },
    { "email": "bob@example.com", "processor_tokens": ["processor-sandbox-xyz789"] }
  ]
}
```

**Response:**

JSON

```json
{
  "success_count": 2,
  "succeeded": [
    { "email": "alice@example.com", "processor_tokens": ["processor-sandbox-abc123"] },
    { "email": "bob@example.com", "processor_tokens": ["processor-sandbox-xyz789"] }
  ],
  "failed": []
}
```

**What to do next:** Direct users to the Bloom enrollment page at `app.bloomplus.com/[organizationslug]`. When they enter their email, Bloom automatically finds their processor token. No invite code is needed. Their bank account is linked automatically.

---

### Mode 2: Invite Tokens

You send an email and a processor token for each user and receive an invite code per user. Once registered via the API, users enter their email and invite code in Bloom+ to begin enrollment. Their bank account is automatically linked via the processor token.

**Request:**

JSON

```json
{
  "expiration_days": 14,
  "tokens": [
    { "email": "alice@example.com", "processor_tokens": ["processor-sandbox-abc123"] }
  ]
}
```

**Response:**

JSON

```json
{
  "success_count": 1,
  "succeeded": [
    {
      "email": "alice@example.com",
      "invite_code": "YZAB-CDEF-GHIJ",
      "processor_tokens": ["processor-sandbox-abc123"]
    }
  ],
  "failed": []
}
```

**What to do next:** Send the user their invite code. When they enter it on the Bloom enrollment page at `app.bloomplus.com/[organizationslug]`, their bank account is linked automatically via the processor token.

---

## Bloom API Response

Every response follows the same shape, regardless of how many tokens succeeded or failed:

JSON

```json
{
  "success_count": 1,
  "succeeded": [ ... ],
  "failed": [ ... ]
}
```

| Field | Type | Description |
| --- | --- | --- |
| `success_count` | integer | How many tokens were successfully created. |
| `succeeded` | array | Tokens that were created. |
| `failed` | array | Tokens that were not created, with reasons. |

Each item in `succeeded`:

| Field | Type | Present when | Description |
| --- | --- | --- | --- |
| `email` | string | Always | The email address. |
| `invite_code` | string | Invite Tokens mode only | The generated invite code (`XXXX-XXXX-XXXX` format). |
| `processor_tokens` | string | Always | The processor tokens you sent. |

Each item in `failed`:

| Field | Type | Description |
| --- | --- | --- |
| `email` | string | The email address that failed. |
| `error` | string | A human-readable reason why it failed. |

### Partial Success

A single request can have some tokens succeed and others fail. The HTTP status will still be `200 OK` even if some tokens failed. Always check both the `succeeded` and `failed` arrays.

Example:

JSON

```json
{
  "success_count": 1,
  "succeeded": [
    { "email": "bob@example.com", "invite_code": "MNOP-QRST-UVWX", "processor_tokens": ["processor-sandbox-xyz789"] }
  ],
  "failed": [
    { "email": "alice@example.com", "error": "email already has an active token" }
  ]
}
```

Bob's token was created. Alice's failed because she already has an active token that hasn't expired yet.

---

## Error reference

### Per-token Errors (inside `failed`)

These errors apply to individual tokens. The request still returns HTTP 200. The error is reported per token in the `failed` array.

| Error message | What it means | What to do |
| --- | --- | --- |
| `invalid email format` | The email is not a valid email address. | Fix the email and retry. |
| `email exceeds maximum length` | The email is longer than 254 characters. | Use a shorter email address. |
| `processor token is required` | Your org requires processor tokens but none was sent. | Add a `processor_tokens` field for this email. |
| `processor token exceeds maximum length` | The processor token is longer than 255 characters. | Check that you're sending the correct token. |
| `duplicate email in batch: <email>` | The same email appears more than once in your request. | Remove the duplicate. |
| `duplicate processor token within email` | The same processor token appears twice under a single email. | Remove the duplicate from that email's token list. |
| `duplicate processor token in batch` | The same processor token appears more than once in your request. | Each email must have a unique processor token. |
| `email already has an active token` | This email already has a token in your org that hasn't expired yet. This applies in both Processor Tokens Only and Invite Tokens modes. | No action needed — the user can already onboard. If you need to reissue, wait for the existing token to expire. |
| `processor token already exists` | This processor token has already been used, possibly by another org. | Generate a new processor token from your financial institution. |
| `email conflict (concurrent request)` | Another request created a token for this email at the same time. | The other request succeeded. Check if the token already exists before retrying. |
| `email or processor token conflict (concurrent request)` | Another request used this email or processor token at the same time. | The other request succeeded. Check if the token already exists before retrying. |

### HTTP Errors

When the API returns an HTTP error, no tokens were created and the entire request is rejected. Processor tokens that were not ingested can be reused in a subsequent call.

| Status | When |
| --- | --- |
| 401 | `x-partner` header is missing, invalid, or the organization was not found. |
| 400 | The request body is malformed, the `tokens` array is empty or exceeds the batch limit, `expiration_days` is out of range, or the organization has neither invite codes nor processor tokens enabled. |
| 500 | An error occurred on Bloom's end. Safe to retry the request. |

---

## Limits

| Limit | Value |
| --- | --- |
| Max tokens per request | 500 |
| Max processor tokens per email, per request | 25 |
| Max expiration days | 365 |
| Default expiration days | 7 |
| Max email length | 254 characters |
| Max processor token length | 255 characters |

---

## What's next

[Appending processor tokens](https://developers.bloomcredit.io/docs/appending-processor-tokens) — add additional bank accounts to a user who has already enrolled and received an invite code.
