> For the complete documentation index, see [llms.txt](https://developers.bead.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers.bead.xyz/onboarding/draft-and-submit.md).

# Draft and Submit (Recommended)

Draft and Submit is the recommended way to start every merchant onboarding application.

Collect what you have, save it as a Draft with a single call, attach supporting PDFs if you have them, and submit the application for signature when you are ready. The same pattern works whether you hold a complete merchant profile or only a merchant name.

{% hint style="success" %}
**Recommended starting point.** `POST /merchant-onboarding/applications` and `POST /merchant-onboarding/applications-short` remain available and fully supported. If you already integrated with either one, nothing changes for you. See [Submit Application](/onboarding/submit-application.md) for those flows.
{% endhint %}

#### Why Draft and Submit

* **One pattern for full and partial data.** Only `partnerId` and `merchantName` are required to create a Draft. Send everything you have today and add the rest later.
* **Nothing reaches the signer until you say so.** A Draft is never sent for signature until you call submit.
* **Attachments before signature.** Upload PDF documents while the application is a Draft.
* **Safe to correct.** Replace the stored data with `PUT`, or discard the Draft entirely.
* **Format and completeness checks wait for submit.** Draft saves do not apply format checks such as EIN or email format, so you can save incomplete data without errors.

#### The flow

1. **Create the Draft.** `POST /merchant-onboarding/applications/drafts` with the data you have inside `merchantData`. Store the returned `applicationId`.
2. **Update the Draft as you collect more data (optional).** `PUT /merchant-onboarding/applications/drafts/{applicationId}` with the full `merchantData`.
3. **Attach documents (optional).** `POST /merchant-onboarding/applications/{applicationId}/attachments`. See [Application Attachments](/onboarding/application-attachments.md).
4. **Submit.** `POST /merchant-onboarding/applications/{applicationId}/submit` with no body. Bead sends the application to the signer.
5. **Track progress.** Poll [Get Status](/onboarding/get-status.md), subscribe to [webhooks](/onboarding/partner-webhooks.md), or both.

A typical status path looks like this:

```
draft → signing → signed → reviewing → reviewed → boarding → boarded
```

#### Endpoints

All endpoints use API key authentication with the `X-Api-Key` header.

| Action            | Endpoint                                                                              | Notes                                                             |
| ----------------- | ------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| Create Draft      | `POST /merchant-onboarding/applications/drafts`                                       | Body is `{ "merchantData": { ... } }`. Returns `applicationId`.   |
| Update Draft      | `PUT /merchant-onboarding/applications/drafts/{applicationId}`                        | Full replace of the stored data. Returns the updated application. |
| Discard Draft     | `DELETE /merchant-onboarding/applications/drafts/{applicationId}`                     | Returns `204`. Permanently deletes the Draft and its attachments. |
| Upload attachment | `POST /merchant-onboarding/applications/{applicationId}/attachments`                  | PDF only. Draft status only.                                      |
| List attachments  | `GET /merchant-onboarding/applications/{applicationId}/attachments`                   | Verify the package before submitting.                             |
| Delete attachment | `DELETE /merchant-onboarding/applications/{applicationId}/attachments/{attachmentId}` | Draft status only.                                                |
| Submit            | `POST /merchant-onboarding/applications/{applicationId}/submit`                       | No request body. Draft status only.                               |

{% hint style="warning" %}
`PUT /merchant-onboarding/applications/drafts/{applicationId}` updates a Draft. `PUT /merchant-onboarding/applications/{applicationId}` is a different endpoint that resends an application that is already in the signer facing flow. See [Resend Application](/onboarding/resend-application.md).
{% endhint %}

#### Request shape

The request body wraps all merchant fields in `merchantData`. The field names inside `merchantData` are the same names used by `POST /merchant-onboarding/applications`, including `feeInformation`, `stakeholders`, and `cryptoEnvironment`.

```json
{
  "merchantData": {
    "partnerId": "partner_123",
    "merchantName": "Northwind Coffee Roasters"
  }
}
```

**Required fields**

| Field                       | Description                   |
| --------------------------- | ----------------------------- |
| `merchantData.partnerId`    | Your Bead partner identifier. |
| `merchantData.merchantName` | The merchant name.            |

Every other field is optional when you save a Draft.

**Strict field names**

Draft requests reject unknown properties with a `400`. This applies to the request wrapper, to `merchantData`, and to each stakeholder. For example, a flat body with `partnerId` at the top level fails with `'partnerId' is not a recognized property.` Always nest merchant fields inside `merchantData`, and use the exact field names shown in the full sample below.

**Field notes**

* Addresses use `address1`, `address2`, `city`, `region`, `country`, and `postalCode`.
* The point of contact uses `phoneNumber`, and so do stakeholders.
* `submitImmediately` is not accepted on Draft requests. You control timing by calling submit.
* Send at most 5 stakeholders, with at most one marked `isApplicationSigner: true`.
* `feeInformation` is optional on a Draft, but when you include it, it is validated. See [Fee Configuration for Onboarding Applications](/onboarding/fee-configuration-for-onboarding-applications.md).
* Set exactly one of `isLegalAddress`, `isOperatingAddress`, and `isVirtualAddress` to `true`. These flags drive the address type shown on the application. Send `businessMailingAddress` when `isOperatingAddress` is `true`.
* `sameAsRegisteredAddress` is accepted but not stored. Send the address you want recorded in `businessMailingAddress`.
* `hasNoOwners: true` tells Bead that no individual owns 25 percent or more of the business.

#### Minimal sample

The smallest valid Draft contains only the two required fields.

```bash
curl --request POST \
  --url https://api.test.devs.beadpay.io/merchant-onboarding/applications/drafts \
  --header "X-Api-Key: {apiKey}" \
  --header "Content-Type: application/json" \
  --header "Accept: application/json" \
  --data '{
    "merchantData": {
      "partnerId": "partner_123",
      "merchantName": "Northwind Coffee Roasters"
    }
  }'
```

Response:

```json
{
  "applicationId": "app-123exampleid"
}
```

Store `applicationId`. Every later call on the application uses it. The `envelopeId` and `status` values are not populated until the application is submitted.

#### Full sample

This Draft carries a complete merchant profile with a signer, banking details, and fee information. Use it as the reference for field names and shapes.

{% code expandable="true" %}

```json
{
  "merchantData": {
    "partnerId": "partner_123",
    "merchantName": "Northwind Coffee Roasters",
    "partnerExternalId": "ext-merchant-2048",
    "registeredName": "Northwind Coffee Roasters LLC",
    "dbaName": "Northwind Coffee Roasters",
    "federalTaxIdType": "ein",
    "federalTaxId": "123456789",
    "naicsCode": "722515",
    "merchantCategoryCode": "5499",
    "businessDescription": "Retail coffee roaster and cafe",
    "proofOfBusinessType": "businessLicense",
    "registrationDate": "2021-04-12",
    "legalEntityType": "llc",
    "grossAnnualRevenue": 1250000,
    "highestMonthlyVolume": 160000,
    "averageTicketSize": 32,
    "maxTicketSize": 500,
    "registeredLegalAddress": {
      "address1": "123 Harbor Street",
      "city": "Boston",
      "region": "MA",
      "country": "US",
      "postalCode": "02110"
    },
    "proofOfAddressType": "utilityBill",
    "businessMailingAddress": {
      "address1": "123 Harbor Street",
      "city": "Boston",
      "region": "MA",
      "country": "US",
      "postalCode": "02110"
    },
    "isLegalAddress": false,
    "isOperatingAddress": true,
    "isVirtualAddress": false,
    "locationBusinessType": "physical",
    "locationName": "Northwind Coffee Roasters",
    "businessWebsite": "https://northwind.example.com",
    "businessEmail": "ops@northwind.example.com",
    "businessPhone": "+15085550100",
    "mainPointOfContact": {
      "firstName": "Morgan",
      "lastName": "Reed",
      "email": "morgan.reed@example.com",
      "phoneNumber": "+15085550101"
    },
    "hasNoOwners": false,
    "stakeholders": [
      {
        "firstName": "Morgan",
        "lastName": "Reed",
        "dateOfBirth": "1987-06-15T00:00:00Z",
        "citizenship": "US",
        "ownershipPercentage": 100,
        "ownershipType": "direct",
        "idType": "passport",
        "idNumber": "123456789",
        "countryOfIssuance": "US",
        "taxIdType": "ssn",
        "taxIdNumber": "123456789",
        "proofOfIdentityType": "passport",
        "proofOfAddressType": "utilityBill",
        "address": {
          "address1": "123 Harbor Street",
          "city": "Boston",
          "region": "MA",
          "country": "US",
          "postalCode": "02110"
        },
        "email": "morgan.reed@example.com",
        "phoneNumber": "+15085550101",
        "jobTitle": "Owner",
        "isApplicationSigner": true
      }
    ],
    "bankName": "First Harbor Bank",
    "routingNumber": "011000015",
    "accountNumber": "1234567890",
    "accountType": "checking",
    "proofOfBankAccountType": "bankLetter",
    "bankDepositMethod": "ach",
    "bankAddress": {
      "address1": "10 Bank Plaza",
      "city": "Boston",
      "region": "MA",
      "country": "US",
      "postalCode": "02111"
    },
    "feeInformation": {
      "achSettlementFixedFee": {
        "sellRate": 1.5,
        "isBilledByPartner": false
      },
      "settlementReturnFixedFee": {
        "sellRate": 15,
        "isBilledByPartner": false
      },
      "monthlyMaintenanceFee": {
        "sellRate": 0,
        "isBilledByPartner": false
      },
      "bitcoinFee": {
        "transactionRate": {
          "sellRate": 2.5,
          "isBilledByPartner": false
        },
        "perItemFee": {
          "sellRate": 0.25,
          "isBilledByPartner": false
        }
      },
      "stablecoinFee": {
        "transactionRate": {
          "sellRate": 2.5,
          "isBilledByPartner": false
        },
        "perItemFee": {
          "sellRate": 0.25,
          "isBilledByPartner": false
        }
      },
      "digitalWalletsFees": [
        {
          "tenderType": "paypal",
          "paymentLocationType": "inStore",
          "transactionRate": {
            "sellRate": 2.29,
            "isBilledByPartner": false
          },
          "perItemFee": {
            "sellRate": 0.09,
            "isBilledByPartner": false
          },
          "refundFee": {
            "sellRate": 0,
            "isBilledByPartner": false
          },
          "chargebackFee": {
            "sellRate": 0,
            "isBilledByPartner": false
          }
        },
        {
          "tenderType": "paypal",
          "paymentLocationType": "online",
          "transactionRate": {
            "sellRate": 3.6,
            "isBilledByPartner": false
          },
          "perItemFee": {
            "sellRate": 0.49,
            "isBilledByPartner": false
          },
          "refundFee": {
            "sellRate": 0,
            "isBilledByPartner": false
          },
          "chargebackFee": {
            "sellRate": 0,
            "isBilledByPartner": false
          }
        }
      ]
    },
    "cryptoEnvironment": "sandbox"
  }
}
```

{% endcode %}

The sample prices PayPal only. For each additional wallet or BNPL tender you price, add an `inStore` row and an `online` row in the same shape. See [Sample Payload](/onboarding/sample-payload.md) for the complete fee reference.

Send it:

```bash
curl --request POST \
  --url https://api.test.devs.beadpay.io/merchant-onboarding/applications/drafts \
  --header "X-Api-Key: {apiKey}" \
  --header "Content-Type: application/json" \
  --header "Accept: application/json" \
  --data @northwind-draft.json
```

#### Update a Draft

Send the complete `merchantData` again to replace what is stored. This is a full replace, not a merge, so any field you leave out is cleared.

The request body is identical to Create a Draft. `applicationId` appears only in the URL.

```bash
curl --request PUT \
  --url https://api.test.devs.beadpay.io/merchant-onboarding/applications/drafts/app-123exampleid \
  --header "X-Api-Key: {apiKey}" \
  --header "Content-Type: application/json" \
  --header "Accept: application/json" \
  --data @northwind-draft-updated.json
```

The response is the updated application. The same strict field name rules apply as on create.

#### Attach documents

Attachments are PDF only and can be added or deleted only while the application is a Draft. Upload each file with a `category`, and include `stakeholderIndex` for stakeholder documents.

```bash
curl --request POST \
  --url https://api.test.devs.beadpay.io/merchant-onboarding/applications/app-123exampleid/attachments \
  --header "X-Api-Key: {apiKey}" \
  --form "file=@proof-of-bank-account.pdf" \
  --form "category=proofOfBankAccount"
```

See [Application Attachments](/onboarding/application-attachments.md) for categories, size limits, and examples.

#### Submit

When the Draft is ready, submit it. The request has no body.

```bash
curl --request POST \
  --url https://api.test.devs.beadpay.io/merchant-onboarding/applications/app-123exampleid/submit \
  --header "X-Api-Key: {apiKey}" \
  --header "Accept: application/json"
```

Response:

```json
{
  "applicationId": "app-123exampleid",
  "envelopeId": "env-1111-2222-3333-4444",
  "status": "signing"
}
```

`envelopeId` is an internal signing reference. You do not need it for any Bead API call.

**What submit checks**

Submit is where completeness is enforced. The request is rejected if any of these are not met:

* the application is in Draft status
* one stakeholder is marked `isApplicationSigner: true`
* attachments, where provided, are PDF files
* each stakeholder has a date of birth
* fee information is complete, including the ACH settlement fixed fee and the settlement return fixed fee
* fees meet the fee group and partner sell rate checks configured for your partner
* the signer email is unique

If submit fails, fix the data with `PUT`, then submit again. The Draft stays in Draft status until a submit succeeds.

**Remaining fields are completed by the signer**

Any application fields still blank at submit can be completed by the signer in Bead's hosted signing experience. Send as much as you have so the signer mainly reviews, confirms, and signs.

#### Discard a Draft

Discard a Draft that is no longer needed.

```bash
curl --request DELETE \
  --url https://api.test.devs.beadpay.io/merchant-onboarding/applications/drafts/app-123exampleid \
  --header "X-Api-Key: {apiKey}"
```

A successful discard returns `204 No Content` and permanently deletes the Draft and its attachments. Discard works only on Draft applications. Calling it on any other status returns `400` with the message `Only Draft applications can be discarded`. To stop an application that has left Draft status, see [Cancel Application](/onboarding/cancel-application.md).

#### Error handling

| Scenario                                                          | Result                                                         |
| ----------------------------------------------------------------- | -------------------------------------------------------------- |
| Missing `partnerId` or `merchantName`                             | `400` validation error.                                        |
| Unknown property in the wrapper, `merchantData`, or a stakeholder | `400`, for example `'partnerId' is not a recognized property.` |
| More than 5 stakeholders, or more than one signer                 | `400` validation error.                                        |
| `feeInformation` present but invalid                              | `400` validation error.                                        |
| Submit on an application that is not a Draft                      | Request rejected.                                              |
| Submit with missing signer, dates of birth, or fee information    | Request rejected with the failing check.                       |
| Discard on a non Draft application                                | `400`, `Only Draft applications can be discarded`.             |
| Unknown `applicationId`                                           | `404 Not Found`.                                               |
| Missing or invalid API key                                        | `401 Unauthorized`.                                            |

#### Best practices

* Start with Draft and Submit for every new integration.
* Save a Draft as soon as you have a merchant name, then enrich it as data arrives.
* Always nest merchant fields in `merchantData` and use the exact field names from the full sample.
* Resend the complete `merchantData` on every `PUT`.
* Mark one stakeholder as the signer before you submit.
* Upload and list attachments before you submit, because they cannot change afterward.
* Store `applicationId` immediately after create.
* Discard abandoned Drafts so your records stay clean.
* Use `GET /merchant-onboarding/applications/{applicationId}` and webhooks to track the application after submit.

#### Related pages

* [Submit Application](/onboarding/submit-application.md)
* [Sample Payload](/onboarding/sample-payload.md)
* [Application Attachments](/onboarding/application-attachments.md)
* [Fee Configuration for Onboarding Applications](/onboarding/fee-configuration-for-onboarding-applications.md)
* [Get Status](/onboarding/get-status.md)
* [Resend Application](/onboarding/resend-application.md)
* [Cancel Application](/onboarding/cancel-application.md)
* [Webhooks for Application Events](/onboarding/partner-webhooks.md)
* [Test the Full Onboarding Workflow in Sandbox](/onboarding/test-the-full-onboarding-workflow-in-sandbox.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://developers.bead.xyz/onboarding/draft-and-submit.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
