Upload a custom certificate
const url = 'https://api.nsin.ir/domains/example.com/ssl/';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"certificate":"example","private_key":"example","hostnames":["example"]}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.nsin.ir/domains/example.com/ssl/ \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "certificate": "example", "private_key": "example", "hostnames": [ "example" ] }'Installs your own certificate and private key for the domain. Include the
full chain (leaf and intermediates) in certificate — a leaf-only
upload makes clients fail chain verification.
hostnames selects which of the certificate’s SANs this upload should
cover; use the eligible list from POST /domains/{domain}/ssl/parse to
pick them. Omitted, it is the apex and its wildcard (example.com,
*.example.com), so the certificate must carry both.
The upload is pinned: those hostnames serve it from now on, ahead of
the certificate NSIN manages, and edge nodes pick it up within seconds.
A certificate browsers would not trust is refused — a private CA (for
example a Cloudflare Origin CA certificate), a self-signed one, or a
chain missing its intermediate (code says which). Requires
ssl.manage and a plan that includes custom certificates.
Authorizations
Section titled “Authorizations ”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “Path Parameters ”The domain name (for example example.com) — not a numeric id.
Example
example.comRequest Body required
Section titled “Request Body required ”object
PEM-encoded certificate chain. Include intermediates — a leaf-only bundle makes clients fail chain verification.
PEM-encoded private key matching the certificate.
Which of the certificate’s SANs this upload should cover. Use the
eligible list from POST /domains/{domain}/ssl/parse.
Example generated
{ "certificate": "example", "private_key": "example", "hostnames": [ "example" ]}Responses
Section titled “ Responses ”Certificate installed.
object
Example generated
{ "message": "example", "domain": "example", "hostnames": [ "example" ], "expires_at": "2026-04-15T12:00:00Z", "issued_at": "2026-04-15T12:00:00Z", "subject": "example", "sans": [ "example" ]}Missing fields, unparseable PEM, an encrypted private key,
key/certificate mismatch, a hostname the certificate does not cover
or that is not part of this domain — or a certificate browsers
would not accept: code is cert_untrusted or
cert_incomplete_chain (with issuer and the raw trust_error),
or cert_expired / cert_not_yet_valid when the certificate is
outside its validity dates (with expires_at / valid_from).
object
Human-readable description of what went wrong.
cert_untrusted — the issuer is not a public CA, or
the certificate is self-signed.
cert_incomplete_chain — the intermediate
certificate is missing; paste the full chain.
cert_expired — the certificate’s notAfter has
passed; renew it and upload the new one.
cert_not_yet_valid — its notBefore is still in
the future.
The certificate’s issuer.
The underlying verification error.
With cert_expired: when the certificate expired.
With cert_not_yet_valid: when the certificate becomes valid.
Examples
{ "error": "This certificate is missing its intermediate certificate. …", "code": "cert_incomplete_chain", "issuer": "CN=R11,O=Let's Encrypt,C=US", "trust_error": "x509: certificate signed by unknown authority"}Missing, malformed, revoked or expired API key. (A valid key whose
account has been deactivated gets 403 account is inactive instead.)
The single error shape used by every endpoint.
object
Human-readable description of what went wrong.
Examples
{ "error": "invalid API key"}The domain has no active plan.
The single error shape used by every endpoint.
object
Human-readable description of what went wrong.
Example
{ "error": "read-only API key"}Read-only key, insufficient role, or the plan does not include custom certificates.
The single error shape used by every endpoint.
object
Human-readable description of what went wrong.
Example
{ "error": "read-only API key"}No such domain, or it is not visible to this account. Domains you cannot access are reported as not found rather than forbidden.
The single error shape used by every endpoint.
object
Human-readable description of what went wrong.
Example
{ "error": "read-only API key"}The key exceeded its request budget (300 requests per minute by default).
The single error shape used by every endpoint.
object
Human-readable description of what went wrong.
Examples
{ "error": "rate limit exceeded"}