Alpaca Broker API — Account Onboarding & KYC
SkillDocs & knowledgeYour AI can open and manage brokerage accounts on Alpaca with this skill. It covers the whole account journey: creating accounts, verifying customer identity, handling disclosures and agreements, uploading documents, and updating or closing accounts. It is aimed at building onboarding, verification, or account-management flows.
Available today. Use it from your connected AI after setup.
No other account needed.
After adding the skill, tell your AI which part of the account flow you want to work on, such as opening accounts, verifying identity, or managing existing accounts. It will then walk through the relevant steps with you.
Then ask your AI: use the Alpaca Broker API — Account Onboarding & KYC skill
What your AI can do with it
- Open new brokerage accounts from start to finish
- Verify customer identity through the required checks
- Collect disclosures and signed agreements
- Upload documents, including W-8BEN forms
- Track an account's status through its lifecycle
- Update account details or close accounts
What this skill tells your AI
The instructions your AI receives, as published by alpacahq/alpaca-skills in skills/broker-api/account-onboarding/SKILL.md and read by ahel’s review.
Create and manage end-user brokerage accounts under your firm. This is the first step of any Broker API integration: no funding, journaling, or trading can happen until an account reaches ACTIVE.
Read
alpaca-broker-integrationfirst for base URLs, auth, and conventions. This skill assumes Broker API + HTTP Basic auth.
Reference
- Guide:
https://docs.alpaca.markets/docs/getting-started-with-broker-api,https://docs.alpaca.markets/docs/accounts - API ref:
https://docs.alpaca.markets/reference/createaccount - Live schema:
alpaca-docsMCP →get-endpointtitle"Broker API"path/v1/accounts
1. Endpoints
| Method | Path | Purpose |
|---|---|---|
| POST | /v1/accounts | Create account (submit application) |
| GET | /v1/accounts | List/query accounts (returns up to 1000) |
| GET | /v1/accounts/{account_id} | Get one account (AccountExtended) |
| PATCH | /v1/accounts/{account_id} | Update account |
| POST | /v1/accounts/{account_id}/actions/close | Close account (returns 204) |
| POST | /v1/accounts/{account_id}/documents/upload | Upload owner/KYC documents (array body) |
| GET | /v1/accounts/{account_id}/documents | List uploaded documents |
| POST / GET | /v1/accounts/{account_id}/cip | Submit / retrieve CIP results |
| GET | /v1/country-info | Supported-country data |
| GET | /v1/events/accounts/status | SSE stream of account-status changes → see alpaca-broker-sse-events |
2. Create-account request (POST /v1/accounts)
Four objects are required: contact, identity, disclosures, agreements. documents and trusted_contact are optional but usually needed for KYC.
{
"contact": {
"email_address": "jane@example.com",
"phone_number": "+15555555555",
"street_address": ["20 N San Mateo Dr"],
"city": "San Mateo",
"state": "CA", // required if country / country_of_tax_residence is USA
"postal_code": "94401",
"country": "USA" // ISO 3166-1 alpha-3
},
"identity": {
"given_name": "Jane",
"family_name": "Doe",
"date_of_birth": "1990-01-01",
"tax_id_type": "USA_SSN", // see enum below
"tax_id": "666-55-4321",
"country_of_tax_residence": "USA",
"funding_source": ["employment_income"]
},
"disclosures": {
"is_control_person": false,
"is_affiliated_exchange_or_finra": false,
"is_politically_exposed": false,
"immediate_family_exposed": false
},
"agreements": [
{ "agreement": "customer_agreement", "signed_at": "2026-01-02T18:09:33Z", "ip_address": "185.13.21.99" }
],
"documents": [ /* OwnerDocumentUploadRequest[] — see §4 */ ],
"trusted_contact": { "given_name": "Jim", "family_name": "Doe", "email_address": "jim@example.com" }
}
Key field rules:
contact.street_addressis an array (max 3 lines).contact.staterequired when country/tax-residence isUSA.identity.funding_sourceis an array; one+ ofemployment_income,investments,inheritance,business_income,savings,family.tax_id_typeenum is large and country-specific:USA_SSN,USA_ITIN,IND_PAN,MEX_RFC,GBR_NINO, … plus genericNATIONAL_ID,PASSPORT,DRIVER_LICENSE,OTHER_GOV_ID,NOT_SPECIFIED. Query the spec for the full list rather than hardcoding.- Optional top-level:
account_type(trading|custodial|donor_advised|ira),account_sub_type(IRA:traditional|roth),enabled_assets(us_equity|us_option|crypto|ipo, defaultus_equity). - Deprecated:
investment_objective/investment_time_horizon/liquidity_needs/risk_tolerancemoved fromidentityto top-level.
Responses: 200 → account object · 409 email already registered · 422 invalid value · 400 malformed body.
3. Agreements
Each entry: agreement (customer_agreement, account_agreement, margin_agreement, crypto_agreement, options_agreement), signed_at (RFC3339), ip_address (IPv4), optional revision. You must present the agreement text to the user and capture the real signing timestamp + IP — Alpaca treats these as the legal record. revision defaults to the currently-active revision if omitted.
4. Documents & W-8BEN
documents[] items: document_type + (content base64 or content_data).
{ "document_type": "identity_verification", "content": "<base64>", "mime_type": "image/jpeg", "document_sub_type": "passport" }
document_typeenum includesidentity_verification,address_verification,date_of_birth_verification,tax_id_verification,w8ben,w9,cip_result, and more.mime_type:application/pdf,image/png,image/jpeg— plusapplication/jsononly forw8ben.- W-8BEN shortcut (lesson): instead of generating a PDF, upload
content_dataas a structuredW8benDocumentJSON object (full_name, country_citizen, permanent_address_*, date_of_birth, ip_address, timestamp, signer_full_name, …) and Alpaca renders the official form for you. This is the clean way to satisfy the tax-form requirement for non-US persons programmatically. - Doc size cap: 10 MB per file when using Alpaca's KYC-as-a-service; no cap if you run your own KYC.
5. Account status lifecycle
status (and crypto_status) use the AccountStatus enum:
| Status | Meaning |
|---|---|
ONBOARDING | Application expected, not yet submitted |
SUBMITTED | Submitted, being processed |
SUBMISSION_FAILED | Submission error |
ACTION_REQUIRED | Needs manual action (e.g. a true disclosure routes here) |
APPROVAL_PENDING | Approval in progress (documented "initial value") |
APPROVED | Approved, waiting to go active |
ACTIVE | Fully usable — funding & trading allowed |
REJECTED | Application rejected |
ACCOUNT_UPDATED | Modified by user |
ACCOUNT_CLOSED | Closed |
INACTIVE | Not enabled for the given asset |
Happy path: SUBMITTED → APPROVAL_PENDING → APPROVED → ACTIVE.
Lesson — gate every downstream op on ACTIVE. A 200 from POST /v1/accounts does not mean tradable. Subscribe to account-status SSE events (or poll GET /v1/accounts/{id}) and only enable funding/journals/trading once status == ACTIVE. Trying to journal or trade into a non-active account fails.
6. KYC results & CIP
kyc_resultson the account object carriesreject/accept/indeterminatecategories (KYCResultTypevalues likeIDENTITY_VERIFICATION,TAX_IDENTIFICATION,ADDRESS_VERIFICATION,WATCHLIST_HIT,COUNTRY_NOT_SUPPORTED,OTHER) plusadditional_information.summaryispass/fail(internal only).- If you run KYC yourself (or via Onfido/Trulioo/Veriff/etc.), submit results via
POST /v1/accounts/{id}/cipwith aCIPInfobody (provider_name, kyc, document, photo, identity, watchlist sub-results). Sub-check results areclear/consider. - Minimum to open an individual account: verify name, date of birth, address, and identification number.
WATCHLIST_HIT/COUNTRY_NOT_SUPPORTEDrequire no user action — Alpaca handles them manually.
7. Integration guidance & lessons learned
- Normalize inputs to canonical formats before sending. Country fields must be ISO 3166-1 alpha-3 (
USA,PHL, …) — strip any UI decoration (flags/emoji, display names) and validate againstGET /v1/country-info. Garbage incountry/country_of_tax_residenceis a common 422. - Capture real agreement metadata.
signed_atandip_addressmust reflect the actual user action, not server time / a placeholder. - Treat creation as async. Persist the returned
account_idimmediately, then drive UI off the status events, not the create response. - Guard against paper/test accounts in production code paths. If you run both sandbox and live, make sure live event handlers reject sandbox/paper account IDs rather than silently mutating real records.
- Idempotency on submit. A
409on duplicate email is your friend — look up the existing account rather than retrying creation. Store your local user↔account_idmapping before the network call so a timeout doesn't orphan an account. - Closing is your responsibility to sequence. Before
POST .../actions/close, you must liquidate all positions and withdraw all cash. The account record is not deleted — it goesACCOUNT_CLOSED.
Related skills: fund the account → alpaca-broker-funding-transfers; move cash in via the firm sweep → alpaca-broker-journals; trade → alpaca-broker-trading-orders; track status in real time → alpaca-broker-sse-events.
Signals
- GitHub stars
- 147
- Forks
- 16
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
alpaca-broker-account-onboarding- Source
- github.com/alpacahq/alpaca-skills