Partner API Documentation
Integrate expert-reviewed 409A valuations into your product: create a valuation, upload documents, track review status, and download the final report PDF, with signed webhooks at every step. The Partner API is rolling out to invited partners. Keys are issued by the partnerships team to approved partners.
Overview
The 409.AI Partner API lets your product offer expert-reviewed 409A valuations as a native feature. Your integration creates a valuation from a submission package, uploads supporting documents, submits it for review, tracks status, and downloads the final report PDF. Signed webhooks keep your system in sync the whole way.
The API is reviewed-final only: it never returns an unreviewed number. Drafts are produced internally in about 24 hours, finals are delivered within 7 business days (express delivery in 1 or 3 business days is available for a $500 fee), and every report is reviewed by CPA, CFA®, and FRM® credentialed professionals before it can be downloaded.
- Base URL: https://platform.409.ai/partner/v1, JSON in and out
- Auth: Authorization: Bearer sk409_... on every request, server-side only
- Interactive reference: full schemas and a try-it console at platform.409.ai/partner/docs
- Data isolation: customer data is used only to prepare that customer's report
The Partner API is rolling out to invited partners. Keys are issued by the partnerships team to approved partners and the integration is scoped together on a call: request API access to get started.
How it works
A valuation moves through a small set of statuses from intake to delivered report. Create it, attach documents, submit it, and our credentialed team takes it from there.
| Status | What it means | What your system does |
|---|---|---|
| received | The submission landed and is queued for analysis | Nothing; wait for the next transition |
| needs_information | The reviewer needs more from the customer | Update the package or upload the missing documents, then submit again |
| in_review | Credentialed professionals are reviewing the report | Nothing; you are notified when review completes |
| final_ready | The reviewed final report is approved | Download report.pdf and deliver it to your customer |
| closed | The valuation was closed (terminal) | Treat it as ended; create a new valuation if needed |
Each transition fires a valuation.status_changed webhook, and report.ready fires when the final PDF becomes available, so most integrations never need to poll.
Authentication
Every request carries your secret key in the Authorization header. Keys are issued by the partnerships team to approved partners, shown once at issuance, and revocable at any time. Treat them like passwords: store them in a secret manager and call the API from your servers only, never from a browser or mobile app.
curl https://platform.409.ai/partner/v1/me \
-H "Authorization: Bearer sk409_..."GET /v1/me returns the partner identity behind the key, which makes it a handy connectivity check. If a key is ever exposed, contact the partnerships team and it will be revoked and reissued.
Quickstart: intake to report
Five calls take a valuation from intake to a delivered report. The full submission package schema lives in the interactive reference.
curl -X POST https://platform.409.ai/partner/v1/valuations \
-H "Authorization: Bearer sk409_..." \
-H "Idempotency-Key: 6b9f6f0e-8d1c-4b3a-9d64-2f9a1c7e5b21" \
-H "Content-Type: application/json" \
-d @submission.jsonResponds 201 with {"id": "18024", "status": "received"}. Set type to "409a" and pass your own customer identifier as external_id; it is scoped to your partnership.
curl -X POST https://platform.409.ai/partner/v1/valuations/18024/documents \
-H "Authorization: Bearer sk409_..." \
-F "file=@captable.xlsx" \
-F "category=captable_documents"Responds 201 per file. Categories: captable_documents, monthly_income_statements, annual_income_statements, balance_sheets, projections_files, and uploads for anything else.
curl -X POST https://platform.409.ai/partner/v1/valuations/18024/submit \
-H "Authorization: Bearer sk409_..."Responds 200 when the package is complete. If anything is missing it responds 422 with a missing[] array naming exactly what to add.
curl https://platform.409.ai/partner/v1/valuations/18024 \
-H "Authorization: Bearer sk409_..."Responds 200 with the current status, for example {"id": "18024", "status": "in_review"}. Prefer webhooks for updates; poll only as a fallback.
curl https://platform.409.ai/partner/v1/valuations/18024/report.pdf \
-H "Authorization: Bearer sk409_..." \
-o report.pdfResponds 200 with the PDF once the valuation is final_ready. Before expert approval it responds 409 with code report_not_ready: only reviewed finals ever leave the API.
Endpoints
| Method | Path | Purpose |
|---|---|---|
| POST | /v1/valuations | Create a valuation from a submission package (Idempotency-Key supported, partner-scoped external_id) |
| PUT | /v1/valuations/{id} | Replace the submission package any time before the report is final |
| POST | /v1/valuations/{id}/documents | Upload a supporting file (multipart: file + category) |
| POST | /v1/valuations/{id}/submit | Submit for review; 422 with missing[] when incomplete |
| GET | /v1/valuations/{id} | Retrieve the valuation and its current status |
| GET | /v1/valuations/{id}/report.pdf | Download the reviewed final report (409 report_not_ready before approval) |
| PUT | /v1/webhook | Create or rotate your webhook endpoint; returns the signing secret |
| GET | /v1/webhook | Inspect the registered webhook endpoint |
| DELETE | /v1/webhook | Remove the webhook endpoint |
| POST | /v1/webhook/test | Send a signed test event to your endpoint |
| GET | /v1/me | Identify the partner behind the API key |
Request and response schemas for every endpoint, with a try-it console, are in the interactive API reference.
v1 accepts one report type today: "409a". The spec already declares the full 13-type catalogue (409A, SMB, ASC 718, IFRS 2, ASC 820, QSBS, gift and estate tax, ESOP, EMI, CSOP, PPA, impairment testing, and IP) in its type enum, so additional types can arrive without a breaking change. Enum values are the spec codes, so SMB is passed as fmv.
Webhooks
Each partner registers one webhook endpoint. PUT /v1/webhook creates or rotates it and returns the whsec_... signing secret exactly once per rotation, so store it immediately.
curl -X PUT https://platform.409.ai/partner/v1/webhook \
-H "Authorization: Bearer sk409_..." \
-H "Content-Type: application/json" \
-d '{"url": "https://api.example.com/webhooks/409ai"}'- Events: valuation.status_changed on every transition, and report.ready when the final PDF is available
- Envelope: {id, type, created_at, data}, delivered as JSON with the event id repeated in the X-409AI-Delivery header
- Signature: X-409AI-Signature: t=<unix>,v1=<hex(HMAC_SHA256(secret, "{t}.{body}"))>
- Retries: failed deliveries retry at 1m, 5m, 30m, 2h, and 12h, then the delivery is marked failed
Verify the signature before trusting any delivery, and reject stale timestamps to block replays:
import hashlib, hmac, time
def verify(signature_header, body, secret, tolerance=300):
parts = dict(item.split("=", 1) for item in signature_header.split(","))
timestamp, received = int(parts["t"]), parts["v1"]
if abs(time.time() - timestamp) > tolerance:
return False
expected = hmac.new(secret.encode(), f"{timestamp}.".encode() + body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, received)POST /v1/webhook/test sends a signed test event on demand, which makes handler development a one-command loop.
Errors
Every error uses one envelope, and every response carries an x-request-id header (mirrored as request_id in error bodies). Log it and include it when you contact support.
{
"error": {
"code": "report_not_ready",
"message": "The report has not been approved for release yet."
},
"request_id": "req_9f2d41c8a7"
}| Code | HTTP | Meaning |
|---|---|---|
| unauthorized | 401 | Missing, malformed, or revoked API key |
| not_found | 404 | The valuation does not exist or belongs to another partner |
| invalid_request | 422 | The request body is malformed or fails validation |
| validation_failed | 422 | The submission is incomplete; missing[] lists what to add |
| idempotency_conflict | 409 | The Idempotency-Key was reused with a different body |
| external_id_conflict | 409 | The external_id is already attached to another valuation |
| locked | 409 | The valuation can no longer be modified |
| report_not_ready | 409 | The final report has not been approved yet |
| payload_too_large | 413 | The uploaded file exceeds the size limit |
| rate_limited | 429 | Too many requests; retry after the Retry-After header |
Limits and versioning
- Rate limits: 120 requests per minute per key, and 20 per minute for document uploads. A 429 includes Retry-After; back off for that many seconds
- Idempotency: send a unique Idempotency-Key (a UUID works well) on POST /v1/valuations so network retries never create duplicates; reusing a key with a different body returns 409 idempotency_conflict
- External ids: external_id is scoped to your partnership and enforced as unique, a second guard against duplicate intakes
The API is versioned in the path: everything documented here lives under /v1. Additive changes (new optional fields, new enum values, new endpoints, new webhook event types) may ship within v1, so build your parsers to ignore fields they do not recognize. Breaking changes will only ever arrive under a new version path.
Frequently asked questions
How do I get an API key?
The Partner API is invite-only. Request access through the partner form on the partners page or write to partners@409.ai, and the partnerships team will scope the integration together with you on a call. Keys are issued to approved partners, shown once at issuance, and can be revoked or rotated at any time.
Is there a sandbox?
Not a public one yet. Onboarding is hands-on: the partnerships team scopes a safe path to production with you on a call, and POST /v1/webhook/test sends signed test events on demand so you can build and verify your webhook handler end to end before real traffic arrives.
Which report types can I create?
v1 accepts the "409a" report type today. The API spec already declares the full 13-type catalogue (409A, SMB, ASC 718, IFRS 2, ASC 820, QSBS, gift and estate tax, ESOP, EMI, CSOP, PPA, impairment testing, and IP) in its type enum, so one integration will cover additional types as they roll out.
Is the report PDF white-labeled?
Yes. Reports delivered through the API carry the partner's branding per your white-label agreement, which is scoped during onboarding. Your customers see your brand on the deliverable.
How fast are reports delivered?
Drafts are produced internally in about 24 hours and final reports are delivered within 7 business days, with express delivery in 1 or 3 business days available for a $500 fee. The API only ever returns the reviewed final: every report is reviewed by CPA, CFA®, and FRM® credentialed professionals before report.pdf becomes available.
How is my customers' data used?
Customer data is used only to prepare that customer's report. We never market to your customers or resell their data.
Request API access or open the interactive API reference.