Create an email address
Auth: Authorization: Bearer nsin_… or X-Api-Key: nsin_… — see API keys.
local_part is the part before @ — ASCII letters, digits and
!#$%&'*+/=?^_\{|}~.-, at most 64 characters, lowercased; a +only when the domain'ssubaddressingis on.actionisforward(with adestination_idfrom the domain owner's account) ordrop. A rule whose destination is not verified yet is stored and goes live on verification. Counts against the plan's max_email_rules. Requires records.edit`.
Path parameters
- domainstringrequiredpath
The domain name (for example
example.com) — not a numeric id.
Request body
Content type: application/json · required
- local_partstring
The part before the
@: ASCII letters, digits and!#$%&'*+/=?^_`{|}~.-, up to 64 characters, lowercased on save. A+is allowed only while subaddressing is on for the domain. - actionstring
What to do with mail to the address. Defaults to
forward.One of:"forward""drop" - destination_idinteger
Required for
forward; from the domain owner's account. - namestring
- enabledboolean
Update only; create always starts enabled.
Responses
201The created rule.
Content type: application/json
- idinteger
- local_partstring
The part before the
@, lowercased. - addressstring
The full address,
local_part@domain. - actionstring
forwarddelivers to the destination;dropaccepts the mail and discards it.One of:"forward""drop" - destination_idinteger | null
The destination mail is forwarded to.
nullfordrop. - destination_emailstring | null
That destination's address.
- destination_verifiedboolean
Whether the destination has confirmed its address; unverified destinations receive nothing.
- enabledboolean
Your switch.
- activeboolean
Whether the address is live right now — enabled, routing on for the domain, and (for
forward) the destination verified. - namestring
Optional label.
- created_atstring (date-time)
- updated_atstring (date-time)
{
"id": 0,
"local_part": "string",
"address": "string",
"action": "forward",
"destination_id": 0,
"destination_email": "string",
"destination_verified": true,
"enabled": true,
"active": true,
"name": "string",
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-01T00:00:00Z"
}400Invalid local part, action or destination (field names it).
Content type: application/json
- errorstringrequired
Human-readable description of what went wrong.
- codestring
Machine-readable reason (
hosts_not_ready,kek_unset,loop,no_mx,unverified). - fieldstring
The offending body field, when one applies.
{
"error": "string",
"code": "string",
"field": "string"
}401Missing, malformed, revoked or expired API key. (A valid key whose
account has been deactivated gets 403 account is inactive instead.)
Content type: application/json
- errorstringrequired
Human-readable description of what went wrong.
{
"error": "invalid API key"
}402The domain has no active plan. The body carries upgrade_url.
Content type: application/json
- errorstringrequired
Human-readable description of what went wrong.
- max_rulesinteger | null
- upgrade_urlstring
{
"error": "This domain does not have an active plan. Purchase a plan for this domain before adding email addresses.",
"upgrade_url": "/plans"
}403The key is read-only, your role lacks the permission, the plan does not
include Email Routing (upgrade_url), or the plan's max_email_rules
is reached — the body then carries max_rules and upgrade_url.
Content type: application/json
- errorstringrequired
Human-readable description of what went wrong.
- max_rulesinteger | null
- upgrade_urlstring
{
"error": "You have reached the maximum number of email addresses for this domain's plan. Upgrade the plan for this domain to add more.",
"max_rules": 50,
"upgrade_url": "/plans"
}404No such domain, or it is not visible to this account. Domains you cannot access are reported as not found rather than forbidden.
Content type: application/json
- errorstringrequired
Human-readable description of what went wrong.
{
"error": "read-only API key"
}409An address with this local part already exists (conflict: local_part).
Content type: application/json
- errorstringrequired
Human-readable description of what went wrong.
- conflictstring
What conflicts (
mx,spf,spf_multiple,external_dns,domain_status,not_enabled,local_part,destination). - recordsarray of EmailConflictRecord
For
mx/spf_multiple— the rows in the way.Item fields
- idinteger
- namestring
- contentstring
- priorityinteger
- record_idinteger
For
spf— the existing SPF row. - contentstring
For
spf— its current value. - mergedstring
For
spf— what it becomes with our include merged in. - destinationEmailDestination
Fields
- idinteger
- emailstring
- verifiedboolean
Whether the address was confirmed through the emailed link.
- verified_atstring | null (date-time)
When it was confirmed.
- created_atstring (date-time)
- last_sent_atstring | null (date-time)
When the last verification mail went out.
- resend_cooldown_secondsinteger
Seconds until another verification mail may be sent; 0 when allowed now.
- in_useinteger
Rules and catch-alls pointing at it.
- last_failurestring
The receiving server's last refusal, when forwards to it are bouncing.
- last_failure_atstring | null (date-time)
When
last_failurewas recorded.
{
"error": "string",
"conflict": "string",
"records": [
{
"id": 0,
"name": "string",
"content": "string",
"priority": 0
}
],
"record_id": 0,
"content": "string",
"merged": "string",
"destination": {
"id": 0,
"email": "string",
"verified": true,
"verified_at": "2026-01-01T00:00:00Z",
"created_at": "2026-01-01T00:00:00Z",
"last_sent_at": "2026-01-01T00:00:00Z",
"resend_cooldown_seconds": 0,
"in_use": 0,
"last_failure": "string",
"last_failure_at": "2026-01-01T00:00:00Z"
}
}429The key exceeded its request budget (300 requests per minute by default).
Content type: application/json
- errorstringrequired
Human-readable description of what went wrong.
{
"error": "rate limit exceeded"
}Example request
curl -X POST "https://api.nsin.ir/domains/example.com/email-routing/rules/" \
-H "Authorization: Bearer $NSIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"local_part": "string",
"action": "forward",
"destination_id": 0,
"name": "string",
"enabled": true
}'