BroadNet
SMPPWire format

SMPP PDU anatomy: header and body

Updated 3 min readStandards-based
Direct answer

Every SMPP message is a PDU (Protocol Data Unit) with a fixed 16-byte header followed by an operation-specific body. The header is four big-endian 4-byte integers: command_length, command_id, command_status and sequence_number. command_length counts the whole PDU including the header, so a receiver reads 4 bytes first, then the rest.

DiagramAn SMPP session between your platform and BroadNet
Your platform (ESME)
BroadNet SMSC
One persistent TCP/TLS connection
  1. bind_transceiverOpen and authenticate the session
  2. bind_transceiver_respSession accepted
  3. submit_smSend a message
  4. submit_sm_respAccepted, message ID returned
  5. deliver_smDelivery receipt or inbound message
  6. deliver_sm_respAcknowledged
  7. enquire_linkKeepalive while idle
§01

The 16-byte header

Every PDU begins with the same four unsigned 32-bit integers in network byte order (big-endian). command_length is the total octet count of the PDU including these 16 header bytes — a parser reads the first 4 bytes, learns the full length, then reads the remainder. command_id identifies the operation. command_status is 0 (ESME_ROK) in requests and carries an error code in responses. sequence_number correlates a request with its response.

SMPP header fields (16 bytes, big-endian)
OffsetFieldSizePurpose
0command_length4 octetsTotal PDU length in octets, header included
4command_id4 octetsOperation identifier (e.g. submit_sm = 0x00000004)
8command_status4 octets0 in a request; error code in a response
12sequence_number4 octetsCorrelates request↔response (0x00000001–0x7FFFFFFF)
§02

command_id and the response bit

Each operation has a command_id. The corresponding response uses the same value with the most-significant bit set (logical OR with 0x80000000). So submit_sm is 0x00000004 and submit_sm_resp is 0x80000004. generic_nack (0x80000000) is the catch-all error response for an unparseable or invalid PDU.

Common command_id values
OperationRequestResponse
generic_nack—0x80000000
bind_receiver0x000000010x80000001
bind_transmitter0x000000020x80000002
query_sm0x000000030x80000003
submit_sm0x000000040x80000004
deliver_sm0x000000050x80000005
unbind0x000000060x80000006
replace_sm0x000000070x80000007
cancel_sm0x000000080x80000008
bind_transceiver0x000000090x80000009
enquire_link0x000000150x80000015
data_sm0x000001030x80000103
§03

The body and how fields are encoded

After the header comes the operation-specific body of mandatory parameters, optionally followed by TLV optional parameters. SMPP uses three field encodings. Integers are fixed-size, unsigned, big-endian. C-Octet Strings are ASCII text terminated by a NULL (0x00), with a declared maximum length that includes the terminator. Octet Strings are raw byte fields whose length is given by a preceding length field (for example short_message, whose size is set by sm_length).

SMPP field encodings
TypeEncoding
IntegerFixed 1/2/4-octet unsigned, big-endian (network byte order)
C-Octet StringNUL-terminated ASCII; max length includes the 0x00 terminator
C-Octet String (Decimal/Hex)As above but restricted to decimal or hex ASCII digits
Octet StringRaw bytes; length supplied by a separate length field, no terminator
§04

A worked example: submit_sm on the wire

A minimal submit_sm PDU. The header's command_length (0x0000003D = 61) is the total byte count; command_id 0x00000004 is submit_sm; command_status 0 marks a request; sequence_number 0x0000000F correlates the response. The body then follows in the fixed field order defined by the spec.

submit_sm header + start of body (annotated)hex
00 00 00 3D   command_length = 61
00 00 00 04   command_id     = submit_sm
00 00 00 00   command_status = ESME_ROK (request)
00 00 00 0F   sequence_number = 15
-- body --
00            service_type    = "" (NULL)
05            source_addr_ton = 5 (alphanumeric)
00            source_addr_npi = 0 (unknown)
42 4E 00      source_addr     = "BN" + NULL
01            dest_addr_ton   = 1 (international)
01            dest_addr_npi   = 1 (E.164/ISDN)
...           destination_addr, esm_class, ... short_message
FAQ

Frequently asked

Does command_length include the header?

Yes. command_length is the total length of the entire PDU in octets, the 16-byte header included. A receiver reads exactly command_length bytes to consume one whole PDU off the TCP stream.

What byte order does SMPP use?

Network byte order — big-endian — for all multi-octet integer fields, including every field in the header. A 4-byte value of 61 is transmitted as 00 00 00 3D.

How are text fields terminated?

Text fields are C-Octet Strings: ASCII characters terminated by a single NULL byte (0x00). An empty C-Octet String is just the NULL byte. The declared maximum length includes that terminator.

What is a generic_nack?

generic_nack (command_id 0x80000000) is the response the receiver returns when a PDU cannot be parsed or is fundamentally invalid — for example a bad command_length or unknown command_id. Its command_status carries the reason.

How does a receiver frame PDUs on the TCP stream?

TCP is a byte stream with no message boundaries, so the receiver reads the first 4 bytes to get command_length, then reads that many total bytes to isolate one complete PDU before parsing the rest of the header and body.

References

Source specifications

The published standards this page is grounded in. Opens in a new tab.

BNMaintained by the BroadNet engineering team·Carrier-grade messaging since 2003
Put it on the wire

Build with a real SMPP bind and REST API.

Request test access with real test keys: send to your own verified number first, then move to production across 200+ countries once your sender identity and routes are approved.