diff --git a/README.md b/README.md
index b5d5aff0..44b96604 100644
--- a/README.md
+++ b/README.md
@@ -317,7 +317,7 @@ You don't have to do anything manually!
1. DirectAdmin API
1. KingHost (https://www.kinghost.com.br/)
1. Zilore (https://zilore.com)
-
+1. Loopia.se API
And:
diff --git a/dnsapi/README.md b/dnsapi/README.md
index 045ed0e1..bc1919de 100644
--- a/dnsapi/README.md
+++ b/dnsapi/README.md
@@ -814,6 +814,28 @@ acme.sh --issue --dns dns_zilore -d example.com -d *.example.com
The `Zilore_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
+## 44. Use Loopia.se API
+User must provide login credentials to the Loopia API.
+The user needs the following permissions:
+
+- addSubdomain
+- updateZoneRecord
+- getDomains
+- removeSubdomain
+
+Set the login credentials:
+```
+export LOOPIA_User="user@loopiaapi"
+export LOOPIA_Password="password"
+```
+
+And to issue a cert:
+```
+acme.sh --issue --dns dns_loopia -d example.com -d *.example.com
+```
+
+The username and password will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
+
# Use custom API
If your API is not supported yet, you can write your own DNS API.
diff --git a/dnsapi/dns_loopia.sh b/dnsapi/dns_loopia.sh
new file mode 100644
index 00000000..5d761187
--- /dev/null
+++ b/dnsapi/dns_loopia.sh
@@ -0,0 +1,227 @@
+#!/usr/bin/env sh
+
+#
+#LOOPIA_User="username"
+#
+#LOOPIA_Password="password"
+
+LOOPIA_Api="https://api.loopia.se/RPCSERV"
+
+######## Public functions #####################
+
+#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
+dns_loopia_add() {
+ fulldomain=$1
+ txtvalue=$2
+
+ LOOPIA_User="${LOOPIA_User:-$(_readaccountconf_mutable LOOPIA_User)}"
+ LOOPIA_Password="${LOOPIA_Password:-$(_readaccountconf_mutable LOOPIA_Password)}"
+ if [ -z "$LOOPIA_User" ] || [ -z "$LOOPIA_Password" ]; then
+ LOOPIA_User=""
+ LOOPIA_Password=""
+ _err "You don't specify loopia user and password yet."
+ _err "Please create you key and try again."
+ return 1
+ fi
+
+ #save the api key and email to the account conf file.
+ _saveaccountconf_mutable LOOPIA_User "$LOOPIA_User"
+ _saveaccountconf_mutable LOOPIA_Password "$LOOPIA_Password"
+
+ _debug "First detect the root zone"
+ if ! _get_root "$fulldomain"; then
+ _err "invalid domain"
+ return 1
+ fi
+ _debug _sub_domain "$_sub_domain"
+ _debug _domain "$_domain"
+
+ _info "Adding record"
+
+ _loopia_add_record "$_domain" "$_sub_domain"
+ _loopia_update_record "$_domain" "$_sub_domain" "$txtvalue"
+
+}
+
+dns_loopia_rm() {
+ fulldomain=$1
+ txtvalue=$2
+
+ LOOPIA_User="${LOOPIA_User:-$(_readaccountconf_mutable LOOPIA_User)}"
+ LOOPIA_Password="${LOOPIA_Password:-$(_readaccountconf_mutable LOOPIA_Password)}"
+ if [ -z "$LOOPIA_User" ] || [ -z "$LOOPIA_Password" ]; then
+ LOOPIA_User=""
+ LOOPIA_Password=""
+ _err "You don't specify LOOPIA user and password yet."
+ _err "Please create you key and try again."
+ return 1
+ fi
+
+ #save the api key and email to the account conf file.
+ _saveaccountconf_mutable LOOPIA_User "$LOOPIA_User"
+ _saveaccountconf_mutable LOOPIA_Password "$LOOPIA_Password"
+
+ _debug "First detect the root zone"
+ if ! _get_root "$fulldomain"; then
+ _err "invalid domain"
+ return 1
+ fi
+
+ xml_content=$(printf '
+
+ removeSubdomain
+
+
+ %s
+
+
+ %s
+
+
+ %s
+
+
+ %s
+
+
+ ' $LOOPIA_User $LOOPIA_Password "$_domain" "$_sub_domain")
+
+ response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
+
+ if ! _contains "$response" "OK"; then
+ _err "Error could not get txt records"
+ return 1
+ fi
+}
+
+#################### Private functions below ##################################
+
+_get_root() {
+ domain=$1
+ _debug "get root"
+
+ domain=$1
+ i=2
+ p=1
+
+ xml_content=$(printf '
+
+ getDomains
+
+
+ %s
+
+
+ %s
+
+
+ ' $LOOPIA_User $LOOPIA_Password)
+
+ response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
+ while true; do
+ h=$(echo "$domain" | cut -d . -f $i-100)
+ if [ -z "$h" ]; then
+ #not valid
+ return 1
+ fi
+
+ if _contains "$response" "$h"; then
+ _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
+ _domain="$h"
+ return 0
+ fi
+ p=$i
+ i=$(_math "$i" + 1)
+ done
+ return 1
+
+}
+
+_loopia_update_record() {
+ domain=$1
+ sub_domain=$2
+ txtval=$3
+
+ xml_content=$(printf '
+
+ updateZoneRecord
+
+
+ %s
+
+
+ %s
+
+
+ %s
+
+
+ %s
+
+
+
+
+ type
+ TXT
+
+
+ priority
+ 0
+
+
+ ttl
+ 60
+
+
+ rdata
+ %s
+
+
+ record_id
+ 0
+
+
+
+
+ ' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain" "$txtval")
+
+ response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
+
+ if ! _contains "$response" "OK"; then
+ _err "Error"
+ return 1
+ fi
+ return 0
+}
+
+_loopia_add_record() {
+ domain=$1
+ sub_domain=$2
+
+ xml_content=$(printf '
+
+ addSubdomain
+
+
+ %s
+
+
+ %s
+
+
+ %s
+
+
+ %s
+
+
+ ' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain")
+
+ response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
+
+ if ! _contains "$response" "OK"; then
+ _err "Error"
+ return 1
+ fi
+ return 0
+}