Before you build

API stability

This API exists because MagicDoor's own applications need it. It is not a versioned product, it can change without notice, and anything you build on it is at your own risk. Read this before you commit to it.

Read this before you build anything

MagicDoor does not offer this API as a product. It is the interface our own applications use, published so that customers who want to automate can. It is not versioned, it carries no compatibility guarantee, and it can change at any time to suit what MagicDoor needs to build next.

If that is not a risk your integration can absorb, do not build on it.

There is no version number anywhere — not in the URL, not in a header, not in the body. There is one live API and you are always on it. So there is no older version to stay on while you catch up, and no window in which two versions run side by side.

Without notice, and without it being a bug, any of this can happen:

  • an endpoint changes shape, moves to a different service, or disappears
  • a field is renamed, removed, or starts meaning something subtly different
  • a new value appears in an enum you were exhaustively matching on
  • a status code changes, or a call that used to succeed starts failing validation
  • a default changes — a page size, a sort order, an optional field's fallback

We will not usually be doing this to break you. Most changes come from moving functionality out of the original MagicDoor application into smaller services, which is ongoing.

You can see the seams in this reference already

Two different pagination envelopes (one says page, the other currentPage). The same resource served by two hosts. Pages marked deprecated that point at their replacement. That is the migration in progress, visible in the documentation — which is a fair preview of the kind of change to expect.

None of this is a promise. It is a realistic read of where the ground is firmer, to help you decide what to lean on.

FirmerLooser
The core records — portfolios, properties, units, leases, tenants — and the ids that join themAnything under a service that is mid-move, especially where the same resource appears twice
Conventions: ids as strings, money as decimals, offset-free timestampsResponse envelopes and field names, which differ between the old application and the newer services
Reading dataWriting data, where business rules and validation change with the product
401 on a bad token, 404 on a record you cannot seeWhich of 400 / 409 / 422 a particular refusal comes back as

The difference between an integration that survives a change and one that pages someone at 2am is mostly in how tolerantly it reads.

  1. Read only the fields you use, and ignore the rest

    Do not deserialise into a strict type that rejects unknown properties. New fields appear regularly and are not a breaking change — a strict parser turns every one of them into an outage.

    If you are on .NET
    // Default behaviour already ignores unknown members. Do not turn that off:
    var options = new JsonSerializerOptions
    {
        UnmappedMemberHandling = JsonUnmappedMemberHandling.Skip, // the default
    };
  2. Treat every enum as open

    Match the values you care about and have a default branch for everything else. A new lease status or work-order urgency should route to "something I do not handle yet", not throw.

  3. Never parse an id

    Ids are opaque strings. Do not cast them to a number, do not assume a length, do not sort by them. Two endpoints do return ids as JSON numbers — those pages say so, and even there you should keep the value as a string in your own code.

  4. Do not depend on ordering you were not promised

    Where a list's sort order matters to you, sort it yourself. Most endpoint pages here deliberately say nothing about order, because the source does not guarantee one.

  5. Keep a smoke test you actually run

    A handful of calls that assert the shapes you depend on, run on a schedule against production. It is the only way you will find out a response changed before your users do.

    # The cheapest possible canary: does a token still work, and does
    # the field your code reads still exist?
    curl -sf --url 'https://api.portal.magicdoor.com/company-app/leases?page=1&pageSize=1' \
         --header "Authorization: Bearer $MAGICDOOR_TOKEN" \
      | jq -e '.items[0].postedBalance != null' > /dev/null \
      || echo 'MagicDoor lease shape changed — check before the next sync run'
  6. Make writes recoverable

    There is no Idempotency-Key header, so a retried POST creates a second record. Record what you sent and what came back, so a failed run can be reconciled rather than replayed blindly. See Errors.

No promises, but our intent:

  • This reference tracks the API. When something changes, the page changes with it. It is generated from the source, so it is the best available account of how the API behaves today.
  • Where an endpoint has moved, its page says so and names the replacement.
  • Support will help you if an integration breaks. Include the traceId from the failing response — see Errors.

What we do not offer: advance notice of changes, a deprecation window, a changelog, a supported client library, or a commitment that anything documented here will exist next month.

This is production, and there is no sandbox

Every call acts on real properties, real tenants and real money. There is no test environment to try things against.

Explore with read-only endpoints, and scope your API key to exactly the permissions you need so a mistake cannot reach further than it should — see Authentication.

If you are building something where an unannounced change is not survivable — a product you sell, a migration you cannot repeat, a financial process with a compliance obligation — talk to us before you start rather than after. Write to support@magicdoor.com and describe what you are building.

We would rather know what people depend on than find out by breaking it.