Just Domain Transfer API

The Transfer API from Just Domain — 2 operation(s) for transfer.

GitHub OpenAPI

Operations 3

POST /api/transfer/precheck Post Transfer Precheck #
GET /api/transfer/precheck Get Transfer Precheck #
POST /api/transfer/dns-snapshot Post Transfer Dns Snapshot #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/justdomain-ai:justdomain-ai-transfer-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

justdomain-ai-transfer-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: just-domain-mcp Transfer API
  version: 0.1.0
tags:
- name: Transfer
paths:
  /api/transfer/precheck:
    post:
      summary: Post Transfer Precheck
      description: Can this domain move to us, what stops it, and what would it cost?
      operationId: post_transfer_precheck_api_transfer_precheck_post
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TransferPrecheckRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransferPrecheckResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Transfer
    get:
      summary: Get Transfer Precheck
      description: The same answer as the POST, in a shape an agent can cite.
      operationId: get_transfer_precheck_api_transfer_precheck_get
      parameters:
      - name: domain
        in: query
        required: true
        schema:
          type: string
          minLength: 3
          maxLength: 253
          description: The domain to check, e.g. 'example.com'.
          title: Domain
        description: The domain to check, e.g. 'example.com'.
      - name: include_records
        in: query
        required: false
        schema:
          type: boolean
          description: Also probe public DNS and return the records on `dns_continuity.records`. Off by default - it is ~57 lookups and the eligibility answer does not need them.
          default: false
          title: Include Records
        description: Also probe public DNS and return the records on `dns_continuity.records`. Off by default - it is ~57 lookups and the eligibility answer does not need them.
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransferPrecheckResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Transfer
  /api/transfer/dns-snapshot:
    post:
      summary: Post Transfer Dns Snapshot
      description: 'The "does this look complete?" step, and the set that fills the zone.


        Public and unauthenticated for the same reason the checker is: this runs

        BEFORE anyone has an account, and a login wall in front of "show me what

        my domain currently serves" loses exactly the customer the page exists to

        find. It reads public DNS and the text the caller uploaded. It touches no

        database and no order.


        Three inputs merged in one place, most authoritative last: the probe,

        then the uploaded BIND export (which came from the authoritative side and

        beats every guess we can make), then whatever the customer typed.


        **Everything is validated here with the SAME function the DNS screen

        uses**, and a record that fails comes back in `invalid` with the reason

        rather than being dropped. The client''s own validation is a convenience;

        this is the gate. It is also where the MX-with-no-priority hole is

        closed - a client computing `Number(null)` gets 0, which is a legal MX

        priority, so an MX with no priority set would otherwise sail through as

        the highest-priority mail route nobody chose.


        Nothing here promises the set is COMPLETE. A probe can only ask for names

        it thought of; `notes` says so in the first line, every time.'
      operationId: post_transfer_dns_snapshot_api_transfer_dns_snapshot_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TransferDnsSnapshotRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransferDnsSnapshotResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Transfer
components:
  schemas:
    TransferPrecheckRequest:
      properties:
        domain:
          type: string
          maxLength: 253
          minLength: 3
          title: Domain
          description: The domain to check, e.g. 'example.com'.
        include_records:
          type: boolean
          title: Include Records
          description: 'Also probe public DNS for the domain''s records and return them on `dns_continuity.records`. Off by default: it is roughly 57 lookups and the eligibility answer does not need them. The transfer wizard''s DNS step turns it on.'
          default: false
      type: object
      required:
      - domain
      title: TransferPrecheckRequest
    DnsRecordProblemOut:
      properties:
        record:
          $ref: '#/components/schemas/DnsRecordOut'
        reason:
          type: string
          title: Reason
      type: object
      required:
      - record
      - reason
      title: DnsRecordProblemOut
      description: A record we would not write, and the reason, in the customer's words.
    TransferPrecheckResponse:
      properties:
        domain:
          type: string
          title: Domain
        tld:
          type: string
          title: Tld
        supported:
          type: boolean
          title: Supported
        checked_at:
          type: string
          title: Checked At
        blockers:
          items:
            $ref: '#/components/schemas/TransferBlockerOut'
          type: array
          title: Blockers
          default: []
        registrar:
          $ref: '#/components/schemas/TransferRegistrarOut'
        nameservers:
          items:
            type: string
          type: array
          title: Nameservers
          default: []
        dns_continuity:
          $ref: '#/components/schemas/DnsContinuityOut'
        price:
          anyOf:
          - $ref: '#/components/schemas/TransferPriceOut'
          - type: 'null'
        source:
          $ref: '#/components/schemas/TransferPrecheckSourceOut'
        ready:
          type: boolean
          title: Ready
          description: 'TRUE only when `blockers` is empty. A convenience over that list that can never disagree with it: anything we could not establish becomes a blocker, so a registry timeout reads as not ready.'
        transfer_url:
          type: string
          title: Transfer Url
          description: The page on justdomain.ai a PERSON opens in a browser to take this further.
        next_step:
          type: string
          title: Next Step
          description: One sentence about what happens next, already matched to this domain's state. Written to be relayed to a person as-is.
        auth_code_policy:
          type: string
          title: Auth Code Policy
          description: Constant. The rule about authorization (EPP) codes, restated in every payload so it travels with the answer.
      type: object
      required:
      - domain
      - tld
      - supported
      - checked_at
      - registrar
      - dns_continuity
      - source
      - ready
      - transfer_url
      - next_step
      - auth_code_policy
      title: TransferPrecheckResponse
      description: 'The public precheck payload. The frontend checker is built against it.


        **Additive only.** Every key below `source` was added after the page

        shipped, and nothing above it may be removed or renamed: the checker

        reads the payload as a typed object, and a renamed key is a blank on a

        public page. `tests/test_transfer_precheck_parity.py` pins the original

        key set.


        The last four fields are the ones the MCP tool `check_domain_transfer`

        has always carried. They come from the same builder

        (`shared/services/transfer_handoff`), so an agent with no MCP client gets

        the same `ready`, the same handoff link, the same next step and - the

        one that matters - the same authorization-code refusal, byte for byte.

        The one key that still differs is the projected date: `new_expiry` here,

        `expected_new_expiry` on the tool.'
    TransferPrecheckSourceOut:
      properties:
        rdap:
          type: boolean
          title: Rdap
        registrar_pricing:
          type: boolean
          title: Registrar Pricing
      type: object
      required:
      - rdap
      - registrar_pricing
      title: TransferPrecheckSourceOut
      description: 'Which sources actually answered on this request.


        `registrar_pricing: false` means the price is missing because we could

        not read it, not because the domain is free to transfer.'
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
            - type: string
            - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
        input:
          title: Input
        ctx:
          type: object
          title: Context
      type: object
      required:
      - loc
      - msg
      - type
      title: ValidationError
    DnsRecordOut:
      properties:
        type:
          type: string
          title: Type
          description: A, AAAA, CNAME, MX, TXT, NS, SRV, CAA.
        name:
          type: string
          title: Name
          description: The absolute host, e.g. 'example.com' or '_dmarc.example.com'.
        value:
          type: string
          title: Value
        ttl:
          type: integer
          title: Ttl
          default: 3600
        prio:
          anyOf:
          - type: integer
          - type: 'null'
          title: Prio
      type: object
      required:
      - type
      - name
      - value
      title: DnsRecordOut
      description: 'One DNS record, in the five fields the rest of the product uses.


        Identical in shape to what the DNS-management screen sends, so a record

        read off somebody else''s nameservers and a record typed into our own

        form are the same object and never need translating between the two.'
    TransferRegistrarOut:
      properties:
        name:
          anyOf:
          - type: string
          - type: 'null'
          title: Name
        iana_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Iana Id
      type: object
      title: TransferRegistrarOut
      description: Who sponsors the domain today, as the REGISTRY reports it.
    TransferDnsSnapshotResponse:
      properties:
        domain:
          type: string
          title: Domain
        checked_at:
          type: string
          title: Checked At
        records:
          items:
            $ref: '#/components/schemas/DnsRecordOut'
          type: array
          title: Records
          default: []
        probed:
          type: boolean
          title: Probed
          default: false
        unreadable:
          type: integer
          title: Unreadable
          default: 0
        notes:
          items:
            type: string
          type: array
          title: Notes
          default: []
        invalid:
          items:
            $ref: '#/components/schemas/DnsRecordProblemOut'
          type: array
          title: Invalid
          default: []
        bind_errors:
          items:
            type: string
          type: array
          title: Bind Errors
          default: []
        bind_skipped:
          items:
            type: string
          type: array
          title: Bind Skipped
          default: []
      type: object
      required:
      - domain
      - checked_at
      title: TransferDnsSnapshotResponse
    TransferDnsSnapshotRequest:
      properties:
        domain:
          type: string
          maxLength: 253
          minLength: 3
          title: Domain
        probe:
          type: boolean
          title: Probe
          description: Run the public-DNS probe. Off to validate an upload alone.
          default: true
        bind_zone:
          anyOf:
          - type: string
            maxLength: 400000
          - type: 'null'
          title: Bind Zone
          description: A BIND-format zone file, as most registrars export it. A documented subset is parsed; anything unreadable comes back in `bind_errors` rather than being dropped in silence.
        records:
          anyOf:
          - items:
              $ref: '#/components/schemas/DnsRecordOut'
            type: array
            maxItems: 400
          - type: 'null'
          title: Records
          description: Records the customer added or corrected by hand.
      type: object
      required:
      - domain
      title: TransferDnsSnapshotRequest
      description: 'Build the record set that will fill the pre-staged zone.


        Three inputs, merged in this order so the most authoritative wins:

        the public-DNS probe, then the uploaded BIND export, then anything the

        customer typed. A zone file exported by the losing registrar beats every

        guess our probe can make, which is why it overrides it.'
    TransferPriceOut:
      properties:
        amount:
          type: string
          title: Amount
        currency:
          type: string
          title: Currency
        term_years:
          type: integer
          title: Term Years
        term_note:
          type: string
          title: Term Note
        new_expiry:
          anyOf:
          - type: string
          - type: 'null'
          title: New Expiry
        is_premium:
          type: boolean
          title: Is Premium
      type: object
      required:
      - amount
      - currency
      - term_years
      - term_note
      - is_premium
      title: TransferPriceOut
    TransferBlockerOut:
      properties:
        code:
          type: string
          title: Code
        detail:
          type: string
          title: Detail
        eligible_at:
          anyOf:
          - type: string
          - type: 'null'
          title: Eligible At
      type: object
      required:
      - code
      - detail
      title: TransferBlockerOut
    DnsContinuityOut:
      properties:
        case:
          type: string
          title: Case
        provider:
          anyOf:
          - type: string
          - type: 'null'
          title: Provider
        detail:
          type: string
          title: Detail
        records:
          items:
            $ref: '#/components/schemas/DnsRecordOut'
          type: array
          title: Records
          default: []
        records_probed:
          type: boolean
          title: Records Probed
          default: false
        records_unreadable:
          type: integer
          title: Records Unreadable
          default: 0
        records_notes:
          items:
            type: string
          type: array
          title: Records Notes
          default: []
      type: object
      required:
      - case
      - detail
      title: DnsContinuityOut
      description: 'Does DNS keep working after the transfer?


        "independent" - the nameservers belong to a DNS provider, not to the

        losing registrar, so a transfer does not touch them. "losing_registrar" -

        the dangerous case: the old registrar eventually stops serving the zone.

        "unknown" - we do not recognise the nameservers, said plainly.


        `records` is the public-DNS probe the wizard renders for its "does this

        look complete?" review. It is only populated when the caller asks for it

        (`include_records`), because the probe is ~57 lookups against public

        resolvers and the checker page does not need them to answer its own

        question. **`records_probed` is how a client tells "we did not look" from

        "there is nothing there"** - an empty `records` with `records_probed:

        false` means the first, and treating it as the second is how somebody

        stages an empty zone.'