Get Started with the Ingest API
The Ingest API brings lease data into Leasecake from a system you are retiring, a platform you keep running beside Leasecake, or a one-time portfolio migration. Send the files you already have or post each lease as structured JSON, and a working integration takes three calls: get a token, submit your data, and poll until the submission settles. This guide walks through that first working submission; the full endpoint reference lives at leasecake.cloud/ingest/v1/docs.
How the API works
Everything you send becomes a draft for a person on your team to review and publish. Nothing you send changes a live lease. Leasecake stores, scans, and classifies each item, then drafts it for review.
Submissions are the unit of work: one or many files sent together, because a migration usually arrives as several export files at once.
Items are what a submission carries: each file, and each lease posted as JSON. Items move through the pipeline independently, so one file needing attention never holds up the rest of the batch.
Drafts are where every lease lands for a person in your workspace to review and publish.
The one exception to the draft rule is opt-in: a lease posted with publish_behavior.publish_if_valid publishes itself, but only when it passes every check a person's publish would run.
Authenticate
The API uses the OAuth 2.0 client credentials grant. Your Leasecake contact issues you a client_id and client_secret for one workspace, and the token you exchange them for identifies both your integration and that workspace. Requests never name a workspace; responses report it as tenant_id.
Exchange your credentials at https://identity.leasecake.cloud/oauth2/token for a bearer token, and send it on every request as Authorization: Bearer <token>. Tokens last one hour, so request a new one when yours expires rather than holding one for the length of a migration.
curl https://identity.leasecake.cloud/oauth2/token \
-d grant_type=client_credentials \
-d client_id="$LEASECAKE_CLIENT_ID" \
-d client_secret="$LEASECAKE_CLIENT_SECRET"Permissions are granted, not requested: Leasecake records which permissions your client holds in the workspace, and a token cannot reach beyond them.
ingest:readreads your workspace's submissions and its lease schema.ingest:writecreates submissions, posts leases, and answers held items.ingest:publishlets a posted lease publish itself throughpublish_behavior.
A client with no grant at all is refused with the client-not-granted error, so confirm the grant before your first call.
Send your first submission
Production requests go to https://leasecake.cloud/ingest/v1 and staging requests to https://staging.leasecake.cloud/ingest/v1. Each environment issues its own credentials: a production token is refused on staging, and the reverse.
Get an access token from the token endpoint shown above.
Submit your files to
POST /submissions. Send them together, and describe each one in theitemsarray so Leasecake does not have to guess what it is. Items can carry anexternal_lease_idto identify the lease on your side.Poll
GET /submissions/{id}with thesubmission_idfrom the response untilclosed_atis set.
The API answers 202 Accepted straight away and does the storing, scanning, and classifying afterwards.
curl https://leasecake.cloud/ingest/v1/submissions \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-F "files[][email protected];type=text/csv" \
-F "files[][email protected];type=application/pdf" \
-F 'items=[{"kind":"structured_data"},{"kind":"lease_document","external_lease_id":"LEASE-2026-0417"}]'Instead of files, you can post each lease as structured JSON to POST /leases. That also creates a submission, and the lease is an item in it.
Requests and responses are JSON, except file uploads, which are multipart/form-data.
Make retries safe
Every request that creates something takes an Idempotency-Key header, so retrying after a timeout or a dropped connection never creates a second submission. Generate a key (a UUID works well) and send the same one with every retry of that request.
Retry with the same key after any failure.
A replay answers with the original submission, marked
Idempotency-Replayed: true.Reusing a key with a different body answers
409idempotency-key-reuse. Only then generate a new key.Keys last at least 24 hours and are scoped to the credential that sent them.
What happens next
Poll the submission until closed_at is set, which means every item has reached a final state. Each item carries an outcome that tells you who acts next. The outcomes waiting on you are ready_for_review (review and publish the draft lease), interrupted (send the same file again), and needs_attention (read the item's reason and act on it). When you see a draft, a person on your team reviews and publishes it in Leasecake before anything goes live.
The full API reference at leasecake.cloud/ingest/v1/docs covers every endpoint, the complete submission lifecycle, and the error catalog. For deeper guides, see Follow a submission and handle outcomes and Ingest API errors and limits.