# Add records with a link

Source: https://modulify.ai/docs/publish/add-records-with-a-link

A service can send you a link that opens Modulify with a set of DNS records for a domain your workspace bought, so you review them and add them in one click.

A mail provider, a store or any other service that needs DNS records on your domain can hand you a link instead of a list to copy. The link opens the **Add DNS records** page in Modulify with the records filled in. Nothing changes until you click **Add records**, and the records Modulify manages for your sites and email domains are never replaced.

It works for a domain the workspace bought on the **Domains** page, see [Buy a domain](https://modulify.ai/docs/publish/buy-a-domain). The first half of this page is for the person who opens such a link. The second half, from [Build the link](https://modulify.ai/docs/publish/add-records-with-a-link#build-the-link), is for the service that makes it.

## Open a link

The link opens `/dashboard/domains/add-records`. If you are signed out you sign in first, and the page loads right after. It looks for the domain in every workspace you belong to, not only the one you have open.

On a phone with the Modulify app for iPhone or Android installed, the link opens the same page in the app, after you sign in if you are signed out.

The page is headed **Add DNS records**, `Records a link asks to add to acme.com.` Under the heading a notice reads **This link came from outside Modulify**, `Modulify cannot tell who made it. Approve it only if you asked a service you trust to set up this domain.` A link cannot carry a name or a logo for the service, because Modulify has no way to check one.

When the domain no longer uses Modulify's nameservers, a second notice reads **This domain uses other nameservers**, `Records added here only take effect once the domain is back on the Modulify nameservers.`, with an **Open nameservers** button. See [Change the nameservers](https://modulify.ai/docs/publish/manage-dns#change-the-nameservers).

## Read the records

Every record of the link is a row, with **Type**, **Name**, **Value** and **TTL** the way the **DNS records** tab shows them, and a **Result** that says what approving would do.

| Result | Meaning |
| --- | --- |
| **Will be added** | The record is new |
| **Already there** | The domain holds a record with the same name, type and value, and for MX and SRV the same priority, so nothing changes. Its TTL stays as it is |
| **Replaces records** | The record takes the place of records the domain holds. Each one is named under the result, for example `Deletes the MX record mx1.old-mail.com` |
| **Cannot be added** | Something blocks the record, and the reason is written under the result |

A link only adds records unless the service marked a record as a replacement, see [Replacing records](https://modulify.ai/docs/publish/add-records-with-a-link#replacing-records). A record that would delete something always says so here first.

The page checks the records again every 5 minutes and whenever you come back to its tab, so the results follow changes made in the meantime.

## Approve or cancel

**Add records** saves every record of the link in one go, and **Cancel** opens the **Domains** page without changing anything. When a record replaces others, a dialog asks first: **Replace 1 record?**, or the number of records, `They are deleted from acme.com, and sites, email or services that rely on them can stop working.`, with **Replace and add**.

The link is all or nothing. One record that cannot be added blocks the rest, so the domain never ends up with half of a setup. **Add records** is then disabled, as it is in these cases:

| Tooltip | Why |
| --- | --- |
| `You do not have permission to do this.` | Your role lacks the **Manage domains** permission. The workspace owner always has it, see [Members and roles](https://modulify.ai/docs/reference/members-and-roles) |
| `Renew this domain before you change it.` | The domain has expired |
| `Nothing can be added while a record is blocked.` | A row reads **Cannot be added** |
| `A domain can hold at most 100 DNS records!` | The link would take the domain past the records it can hold |
| `Every record is already in place.` | Every row reads **Already there** |

After a save the **Records added** toast reads `They usually take a few minutes to reach every DNS server.`, and the page shows **Records added**, `DNS servers pick them up within minutes.`, with an **Open DNS records** button that opens the domain's page. Modulify does not send you back to the service and tells it nothing, so go back to the service yourself and let it check the domain.

If saving fails, the **Could not add records** toast gives the reason. When a save stops part way, Modulify puts back what it changed, and the reason ends with `No record was changed!`, or with `Only some of the records were saved, so check the DNS records of this domain!` when it could not.

## Records Modulify never replaces

The records Modulify adds for a site or an email domain of the workspace, the ones with a lock on the **DNS records** tab, are never replaced or deleted by a link. A record of the link that clashes with one reads **Cannot be added**, and the reason names the site or the email domain that holds it, for example `acme.com is managed for acme.com on the site Acme Store, so its address records cannot be changed here. Remove acme.com from that site first!` See [Locked records](https://modulify.ai/docs/publish/manage-dns#locked-records).

## When the page cannot show the records

| What the page shows | When |
| --- | --- |
| **Link not valid**, `This link carries no records to add.` | The link has no `domain`, its `records` are missing, empty or not a JSON list, or its query string is longer than 8,192 characters |
| **Link not valid**, with the reason | The records cannot be read as a set, for example `One request can hold at most 20 DNS records!` or `Every DNS record needs a type, a host and a value!` |
| **Domain not found**, `None of your workspaces holds this domain.` | No workspace you belong to bought that domain |
| **Open this page directly**, `Records cannot be approved inside another page.` | The page was opened inside another page, such as the preview of a site in the editor. Open the link in a tab of its own. Other websites cannot show Modulify pages inside theirs at all |
| **Could not check records**, with the reason and a **Try again** button | Something that can pass, for example `This domain is not registered yet!` while a purchase is still pending or `You are loading DNS records too fast. Try again in 42 seconds!` The page also tries again by itself every 10 seconds |

## Build the link

The link is the **Add DNS records** page with two query parameters.

```text
https://modulify.ai/dashboard/domains/add-records?domain=acme.com&records=<URL-encoded JSON>
```

| Parameter | Value |
| --- | --- |
| `domain` | The bought domain itself, such as `acme.com`. Not a name under it: `shop.acme.com` goes in a record's `host` as `shop` |
| `records` | A JSON list of records, URL-encoded. Up to 20 records |

The query string, everything from the `?` on, can be up to 8,192 characters once encoded.

```javascript
const records = [
    { type: 'TXT', host: '@', value: 'example-verification=7f3a9c' },
    { type: 'MX', host: '@', value: 'mx.example.com', priority: 10, replace: true },
    { type: 'CNAME', host: 'shop', value: 'stores.example.com' }
]

const link = `https://modulify.ai/dashboard/domains/add-records?domain=${encodeURIComponent('acme.com')}&records=${encodeURIComponent(JSON.stringify(records))}`
```

There is nothing to register and no key. Modulify has no lookup that tells a service whether a domain was bought here, so offer the link as an option the person picks.

### What a link can and cannot do

A link can:

- Add records of every type the **DNS records** tab takes: A, AAAA, ANAME, CNAME, MX, NS, SRV and TXT.
- Carry up to 20 records, on the domain itself and on any name under it.
- Ask for a record to take the place of the person's own records at its name, with `replace`. See [Replacing records](https://modulify.ai/docs/publish/add-records-with-a-link#replacing-records).

A link cannot:

- Change or delete a record Modulify manages for a site or an email domain.
- Delete a record without putting one in its place, or change the TTL of a record that is already there.
- Change anything besides DNS records, such as the nameservers or the registrant.
- Show the name or the logo of the service, send the person back to it, or tell it what they did.
- Work on a domain that was not bought on the **Domains** page. A custom domain bought elsewhere keeps its DNS at its own host, see [DNS records](https://modulify.ai/docs/publish/dns-records).

### Record fields

The fields are the ones `create_dns_record` takes, plus `replace`.

| Field | Required | Value |
| --- | --- | --- |
| `type` | Yes | `A`, `AAAA`, `ANAME`, `CNAME`, `MX`, `NS`, `SRV` or `TXT` |
| `host` | Yes | The name relative to the domain: `@` for the domain itself, `www` for `www.acme.com`. A full name such as `www.acme.com` is read as `www`. A CNAME record cannot sit on `@`, use an ANAME record there, and an ANAME record can only sit on `@`. An NS record cannot sit on `@` either |
| `value` | Yes | An IPv4 address for A, an IPv6 address for AAAA, the text for TXT, and a full hostname for ANAME, CNAME, MX, NS and SRV |
| `priority` | For MX and SRV | A whole number from 0 to 65535 |
| `weight` | For SRV | A whole number from 0 to 65535 |
| `port` | For SRV | A port from 1 to 65535 |
| `ttl` | No | Seconds DNS servers keep the record, from 300 to 604800. Defaults to 300 |
| `replace` | No | `true` lets the record take the place of the records it clashes with. Left out, the record is only ever added |

Names and values follow the rules of the **Add record** dialog, see [The name](https://modulify.ai/docs/publish/manage-dns#the-name) and [The value](https://modulify.ai/docs/publish/manage-dns#the-value).

### Replacing records

Without `replace`, a record is added next to what the domain already holds. If it cannot exist next to a record that is there, it is blocked, by the rules under [Records that cannot exist together](https://modulify.ai/docs/publish/manage-dns#records-that-cannot-exist-together): a CNAME record at a name that holds anything else, for example, or a second SPF record.

With `replace` set to `true`, the record takes the place of the records at its name that it clashes with, once the person confirms:

| The record | Replaces at its name |
| --- | --- |
| CNAME | Every other record |
| A, AAAA or ANAME | The A, AAAA and ANAME records, and a CNAME record |
| MX | The other MX records, and a CNAME record |
| SRV | The other SRV records, and a CNAME record |
| TXT | A CNAME record, and for an SPF record the SPF record that is there |
| NS | Nothing. An NS record is only ever added |

A record of the link that the domain already holds is kept and never deleted, so a link with two MX records and `replace` leaves exactly those two. Other TXT records are never replaced. Replacing an SPF record drops what the old one allowed, so include it in the new one.

These are blocked whatever `replace` says:

- A record that clashes with one Modulify manages, see [Records Modulify never replaces](https://modulify.ai/docs/publish/add-records-with-a-link#records-modulify-never-replaces).
- The same record twice in one link, with `This record is in the request twice!`
- A record without a `host`, with `Name is required. Use @ for the domain itself!`
- A record at or under a name that an NS record hands to other nameservers. An NS record the domain holds is never replaced.
- An NS record at a name that holds other records, at that name or under it, because those records would stop answering.

A link that would take the domain past 100 records cannot be approved either.

### After the person approves

Modulify does not redirect to your service and does not call it. Look the records up to see that they are there, and keep looking for a few minutes, since that is how long a new record usually takes to reach every DNS server.

```bash
dig +short TXT acme.com
```

Opening the link again is safe. Records that were added read **Already there**, and **Add records** stays disabled once nothing is left to add.

## From an AI client or the HTTP API

`preview_dns_records` returns the same results for a set of records, and `apply_dns_records` saves it, for an AI client connected over MCP or your own code through the [HTTP API](https://modulify.ai/docs/api). They take the same record fields and follow the same rules, with a token that holds `domains:read` to preview and `domains:write` to save.

## Limits

| Limit | Value |
| --- | --- |
| Records in one link | 20 |
| Length of the link's query string | 8,192 characters |
| Records on one domain | 100 |

Each check of the page counts as a record load, 20 a minute per person, and a save counts as one change toward the workspace's 30 domain changes a minute. See [Limits](https://modulify.ai/docs/publish/manage-dns#limits).

## Next

- [Manage DNS for a bought domain](https://modulify.ai/docs/publish/manage-dns) covers adding, editing and deleting records by hand, and the records Modulify manages.
- [Buy a domain](https://modulify.ai/docs/publish/buy-a-domain) covers buying, renewing and the **Settings** tab.
- [Domain HTTP API](https://modulify.ai/docs/publish/domain-http-api) checks which domains are free from any website or script.