PortSMS finden Sie unter portsms.com. Ihre persönliche Aufladeadresse steht nach der Anmeldung auf der Seite Guthaben bereit.

PortSMS

SMS-API-Referenz

JSON über HTTPS. Erstellen Sie nach Ihrer ersten Aufladung einen Schlüssel auf der Seite API-Schlüssel und senden Sie ihn als Bearer-Token mit.

Basisadresse und Schlüssel

Alle Aufrufe gehen an die unten stehende Adresse. Senden Sie Ihren Schlüssel im Authorization-Header. Wer den Schlüssel besitzt, kann Ihr Guthaben ausgeben, bewahren Sie ihn daher nur auf Ihrem Server auf.

https://portsms.com/api/v1
Authorization: Bearer psm_your_api_key
Content-Type: application/json

Limits: 300 Aufrufe pro Minute und Konto, 1.000 Empfänger pro Anfrage, 50,000 Nachrichten pro Konto innerhalb von 24 Stunden.

Nachricht senden

Sendet einen Text an eine oder mehrere Nummern. Die Nummern müssen im internationalen Format vorliegen (+ und Ländervorwahl). Die gesamten Kosten werden bei Annahme der Anfrage von Ihrem Guthaben abgebucht; Nummern, die wir nicht bedienen können, werden in rejected zurückgegeben und nicht berechnet.

POST/api/v1/messages

toString oder ArrayEmpfängernummern, bis zu 1.000. Jeder Eintrag kann auch ein Objekt { "to": "+1415...", "vars": ["Alice"] } sein, dessen vars {{1}}, {{2}} im Text füllen
textStringNachrichtentext, bis zu 10 Teile pro Empfänger
nameString, optionalEin Name für den Versand, der in Ihrem Verlauf angezeigt wird (80 Zeichen)
schedule_atString, optionalStartzeit im Format ISO 8601, 5 Minuten bis 29 Tage im Voraus. Wird sofort berechnet; stornieren Sie vor dem Start, um den vollen Betrag erstattet zu bekommen
opt_outBoolean, optionaltrue fügt am Ende in einer neuen Zeile "Reply STOP to opt out" hinzu
refString, optionalIhre eigene Referenz, wird in Webhooks zurückgegeben (64 Zeichen)
curl https://portsms.com/api/v1/messages \
  -H "Authorization: Bearer $PORTSMS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to": ["+14155550123", "+447700900123"],
       "text": "Your code is 482913",
       "name": "Login codes",
       "ref": "order-1042"}'
// One text, filled in per recipient, sent tomorrow at 09:00 UTC with an opt-out line
{"to": [{"to": "+14155550123", "vars": ["Alice", "A-1042"]},
        {"to": "+447700900123", "vars": ["Ben", "A-1043"]}],
 "text": "Hi {{1}}, your order {{2}} has shipped.",
 "schedule_at": "2026-10-14T09:00:00Z",
 "opt_out": true}
HTTP/1.1 201 Created
{
  "campaign": {
    "id": "c_7kq2m9xd4tpa", "name": "Login codes", "source": "api",
    "text": "Your code is 482913", "encoding": "gsm7", "parts": 1,
    "recipients": 2, "cost": "0.0440", "refunded": "0.0000",
    "status": "sending", "ref": "order-1042", "scheduled_at": null,
    "created_at": "2026-10-13T09:30:00.000Z", "done_at": null
  },
  "messages": [
    { "id": "m_3hx8q2vkd7mrtc", "campaign_id": "c_7kq2m9xd4tpa", "to": "+14155550123",
      "country": "US", "status": "queued", "error": null, "parts": 1, "price": "0.0090",
      "created_at": "2026-10-13T09:30:00.000Z", "sent_at": null, "done_at": null }
  ],
  "rejected": []
}
// Node.js 18+
const res = await fetch("https://portsms.com/api/v1/messages", {
  method: "POST",
  headers: { Authorization: "Bearer " + process.env.PORTSMS_KEY, "Content-Type": "application/json" },
  body: JSON.stringify({ to: ["+14155550123"], text: "Your code is 482913" }),
});
const data = await res.json();
# Python 3 with requests
import os, requests
r = requests.post("https://portsms.com/api/v1/messages",
    headers={"Authorization": "Bearer " + os.environ["PORTSMS_KEY"]},
    json={"to": ["+14155550123"], "text": "Your code is 482913"})
print(r.status_code, r.json())

Kosten vor dem Senden berechnen

Gleicher Body wie beim Senden. Liefert Kodierung, Teile, Kosten und die Nummern, die abgelehnt würden, und sendet nichts.

POST/api/v1/estimate

{ "encoding": "gsm7", "characters": 19, "parts": 1, "recipients": 2,
  "cost": "0.0440", "balance": "120.00",
  "rejected": [ { "to": "4155550123", "reason": "format" } ] }

Einzelne Nachricht prüfen

Status eines Empfängers anhand der id, die beim Senden zurückgegeben wurde.

GET/api/v1/messages/{id}

{ "message": { "id": "m_3hx8q2vkd7mrtc", "to": "+14155550123", "status": "delivered",
  "error": null, "price": "0.0090", "done_at": "2026-10-13T09:30:06.000Z", ... } }

Kampagnen

Jede Sendeanfrage ist eine Kampagne mit dem Status scheduled, sending, done oder canceled. Listen Sie Ihre letzten 100 auf, öffnen Sie eine, um die Anzahl pro Status und jeden Empfänger zu sehen (500 pro Seite, ?page=2 für weitere), oder stornieren Sie eine geplante mit POST /api/v1/campaigns/{id}/cancel und erhalten Sie den vollen Betrag zurück.

GET/api/v1/campaigns

GET/api/v1/campaigns/{id}?page=1

POST/api/v1/campaigns/{id}/cancel

{ "campaign": { "id": "c_7kq2m9xd4tpa", "status": "done", "recipients": 2,
    "counts": { "queued": 0, "sent": 0, "delivered": 1, "failed": 1 }, ... },
  "messages": [ ... ], "page": 1, "page_size": 500 }

Guthaben und Preise

Ihr Guthaben in US-Dollar und der Preis pro Teil für jedes Land im Angebot.

GET/api/v1/balance

GET/api/v1/prices

{ "balance": "120.00", "currency": "USD", "plan": "basic", "discount_percent": 3 }

{ "prices": [ { "country": "US", "name": "United States", "dial_code": "+1", "price_per_part": "0.0090" }, ... ] }

Nachrichtenstatus

queuedAngenommen und berechnet, wartet auf die Übergabe an die Carrier-Route
sentAn die Carrier-Route übergeben, wartet auf einen Zustellbericht
deliveredDer Netzbetreiber hat die Zustellung an das Telefon gemeldet
failedAbgelehnt oder nicht zustellbar. Der Preis wurde Ihrem Guthaben erstattet

Zustell-Webhooks

Hinterlegen Sie auf der Seite API-Schlüssel eine https-Adresse. Sobald eine Nachricht delivered oder failed ist, senden wir sie per POST als JSON. Wir versuchen es bis zu 8 Mal über etwa zwei Stunden erneut, bis Ihr Server mit einem 2xx-Status antwortet.

POST https://your-server.example/portsms
X-PortSMS-Signature: t=1791883806,v1=5f2c...e91a
Content-Type: application/json

{ "event": "sms.status",
  "data": { "id": "m_3hx8q2vkd7mrtc", "campaign_id": "c_7kq2m9xd4tpa", "to": "+14155550123",
            "country": "US", "status": "delivered", "error": null, "parts": 1, "price": "0.0090",
            "ref": "order-1042", "done_at": "2026-10-13T09:30:06.000Z", ... } }

Prüfen Sie den X-PortSMS-Signature-Header: t ist eine Unix-Zeit und v1 ist der HMAC-SHA256 von "t.body" mit Ihrem Signaturgeheimnis. Lehnen Sie Anfragen ab, die älter als fünf Minuten sind.

// Node.js: verify before trusting the body
import crypto from "node:crypto";
function verify(raw, header, secret) {
  const m = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(header || "");
  if (!m || Math.abs(Date.now() / 1000 - Number(m[1])) > 300) return false;
  const want = crypto.createHmac("sha256", secret).update(m[1] + "." + raw).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(want), Buffer.from(m[2]));
}

Fehler

Fehler werden als JSON mit einem Fehlercode und einem HTTP-Status zurückgegeben.

HTTP/1.1 402 Payment Required
{ "error": "insufficient_balance", "cost": "44.0000" }
bad_key401Der Schlüssel fehlt oder ist falsch
no_deposit403Die API wird freigeschaltet, sobald Ihre erste Aufladung gutgeschrieben ist
insufficient_balance402Das Guthaben ist niedriger als die Kosten (cost ist enthalten)
no_recipients400Keine Nummer konnte angenommen werden (rejected nennt die Gründe)
too_many_recipients413Mehr als 1.000 Nummern in einer Anfrage
empty_text400Der Text ist leer
text_too_long400Der Text benötigt mehr als 10 Teile
bad_schedule400schedule_at ist keine Zeit zwischen 5 Minuten und 29 Tagen im Voraus
daily_limit429Das 24-Stunden-Nachrichtenlimit des Kontos ist erreicht
rate_limited429Mehr als 300 Aufrufe in einer Minute
not_found404Diese Nachricht, Kampagne oder Adresse existiert nicht
not_scheduled409Nur eine geplante Kampagne, die noch nicht begonnen hat, kann storniert werden

Warum eine Nummer abgelehnt wird

formatNicht im internationalen Format, zu kurz oder zu lang
countryEin Land, das wir nicht bedienen
priceEin Land, das derzeit nicht im Angebot ist
duplicateDieselbe Nummer kommt in einer Anfrage zweimal vor
too_longMit eingesetzten vars ist der Text länger als 10 Teile