%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#ecf0f1', 'noteTextColor': '#2C3E50', 'noteBkgColor': '#fff9e6', 'textColor': '#2C3E50', 'fontSize': '13px'}}}%%
flowchart TB
subgraph Message["CoAP Message Format"]
direction TB
Header["Fixed Header (4 bytes)<br/>Ver | Type | TKL | Code | Message ID"]
Token["Token (0-8 bytes)<br/>For request/response matching"]
Options["Options (variable length)<br/>URI, Content-Format, etc."]
Marker["Payload Marker (0xFF)<br/>Separates options from payload"]
Payload["Payload (application data)<br/>Sensor readings, commands, etc."]
end
Header --> Token --> Options --> Marker --> Payload
style Header fill:#2C3E50,stroke:#16A085,stroke-width:2px,color:#fff
style Token fill:#16A085,stroke:#2C3E50,stroke-width:2px,color:#fff
style Options fill:#E67E22,stroke:#2C3E50,stroke-width:2px,color:#fff
style Marker fill:#7F8C8D,stroke:#2C3E50,stroke-width:2px,color:#fff
style Payload fill:#16A085,stroke:#2C3E50,stroke-width:2px,color:#fff
1221 CoAP Message Format and Structure
1221.1 Learning Objectives
By the end of this chapter, you will be able to:
- Decode CoAP Headers: Interpret the 4-byte fixed header byte-by-byte
- Understand Options Encoding: Parse CoAP options using delta compression
- Apply Response Codes: Use proper 2.xx/4.xx/5.xx codes in implementations
- Match Tokens to Requests: Implement proper request-response correlation
1221.2 Prerequisites
Before diving into this chapter, you should be familiar with:
- CoAP Introduction - Understanding why CoAP exists and its design goals
- Binary number representation (bits, bytes, hexadecimal notation)
1221.3 The CoAP Message Format
Core Concept: A CoAP message consists of a 4-byte fixed header, optional token (0-8 bytes), zero or more options, and an optional payload. The fixed header contains version, message type, token length, method/response code, and message ID.
Why It Matters: Understanding the binary format is essential for debugging network captures, implementing CoAP libraries, and optimizing message sizes for constrained networks where every byte counts.
Key Takeaway: The 4-byte header efficiency is CoAP’s main advantage over HTTP - it encodes everything needed for request-response matching, reliability selection, and method identification in just 32 bits.
CoAP messages follow a compact binary format designed for efficiency:
1221.4 The 4-Byte Fixed Header
The fixed header contains all essential message metadata in just 32 bits:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Ver| T | TKL | Code | Message ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Field | Bits | Description |
|---|---|---|
| Ver | 2 | Version (always 01 for CoAP 1.0) |
| T | 2 | Type: CON (00), NON (01), ACK (10), RST (11) |
| TKL | 4 | Token Length (0-8 bytes) |
| Code | 8 | Method (0.xx) or Response (2.xx-5.xx) |
| Message ID | 16 | For deduplication and ACK matching |
1221.4.1 Header Fields Explained
Version (Ver): Always 01 binary (value 1) for CoAP RFC 7252.
Type (T): Determines reliability and message flow:
| Type | Binary | Name | Purpose |
|---|---|---|---|
| CON | 00 | Confirmable | Reliable, requires ACK |
| NON | 01 | Non-confirmable | Fire-and-forget |
| ACK | 10 | Acknowledgment | Confirms CON receipt |
| RST | 11 | Reset | Rejects message |
Token Length (TKL): Number of token bytes (0-8). Tokens correlate responses to requests.
Code: Split into class (3 bits) and detail (5 bits), formatted as class.detail:
| Class | Range | Meaning |
|---|---|---|
| 0 | 0.01-0.04 | Methods (GET, POST, PUT, DELETE) |
| 2 | 2.01-2.05 | Success responses |
| 4 | 4.00-4.15 | Client error |
| 5 | 5.00-5.05 | Server error |
Message ID: 16-bit identifier for: - Matching ACK/RST to CON messages - Detecting duplicate messages (server caches for ~247 seconds)
Sammy the Sensor says: “Imagine sending a message in a bottle! The CoAP header is like the label you put on the bottle.”
The label tells you: - Type: “Please write back!” (CON) or “No reply needed” (NON) - Code: What you want - “Can I have the temperature?” (GET) - Message ID: A number so you know which bottle they’re answering
Just like how a bottle label is tiny compared to the letter inside, CoAP’s header is tiny (4 bytes!) compared to HTTP’s headers (hundreds of bytes!).
1221.5 CoAP Method Codes
CoAP methods mirror HTTP methods but use numeric codes:
| Code | Method | Description | Idempotent |
|---|---|---|---|
| 0.01 | GET | Retrieve resource | Yes |
| 0.02 | POST | Create resource or submit data | No |
| 0.03 | PUT | Update/replace resource | Yes |
| 0.04 | DELETE | Remove resource | Yes |
An idempotent method produces the same result regardless of how many times it’s called: - GET /temperature returns current temperature (safe to retry) - PUT /led {"on": true} sets LED on (calling twice = same result) - DELETE /alarm/5 removes alarm 5 (calling twice = same result, even if already deleted)
POST is NOT idempotent - POST /log {"event": "click"} creates new entry each time.
Why this matters: When a CON message times out, CoAP can safely retry idempotent methods. For POST, the application must handle potential duplicates.
1221.6 Response Codes
CoAP uses a structured response code system similar to HTTP:
1221.6.1 Success (2.xx)
| Code | Name | HTTP Equivalent | Use Case |
|---|---|---|---|
| 2.01 | Created | 201 Created | POST created new resource |
| 2.02 | Deleted | 200 OK (for DELETE) | Resource removed |
| 2.03 | Valid | 304 Not Modified | Cached response still valid |
| 2.04 | Changed | 200 OK (for PUT) | Resource updated |
| 2.05 | Content | 200 OK | GET successful with payload |
1221.6.2 Client Error (4.xx)
| Code | Name | HTTP Equivalent | Cause |
|---|---|---|---|
| 4.00 | Bad Request | 400 | Malformed request |
| 4.01 | Unauthorized | 401 | Missing authentication |
| 4.03 | Forbidden | 403 | Access denied |
| 4.04 | Not Found | 404 | Resource doesn’t exist |
| 4.05 | Method Not Allowed | 405 | Wrong method for resource |
| 4.12 | Precondition Failed | 412 | ETag mismatch |
| 4.15 | Unsupported Content-Format | 415 | Unknown payload format |
1221.6.3 Server Error (5.xx)
| Code | Name | HTTP Equivalent | Cause |
|---|---|---|---|
| 5.00 | Internal Server Error | 500 | Server crashed |
| 5.01 | Not Implemented | 501 | Method not supported |
| 5.02 | Bad Gateway | 502 | Proxy error |
| 5.03 | Service Unavailable | 503 | Server overloaded |
| 5.04 | Gateway Timeout | 504 | Proxy timeout |
1221.7 Token: Request-Response Matching
The Token correlates responses to requests, especially important when multiple requests are in flight:
Client sends: GET /temperature, Token=0xAB12, MsgID=0x5678
Client sends: GET /humidity, Token=0xCD34, MsgID=0x5679
Server sends: 2.05 Content, Token=0xCD34, "65%" (humidity response)
Server sends: 2.05 Content, Token=0xAB12, "22.5" (temperature response)
Token vs. Message ID:
| Aspect | Token | Message ID |
|---|---|---|
| Purpose | Match response to request | Deduplication, ACK matching |
| Scope | Application-level | Transport-level |
| Length | 0-8 bytes (TKL field) | Fixed 16 bits |
| Persistence | Across retransmissions | Changes on each transmission |
| Generated by | Client | Client |
In secure deployments (DTLS), tokens should be unpredictable (randomly generated) to prevent response spoofing attacks. A malicious actor who can predict tokens could inject fake responses.
# BAD: Sequential tokens (predictable)
token = counter
counter += 1
# GOOD: Random tokens (unpredictable)
import os
token = os.urandom(4) # 4 random bytes1221.8 CoAP Options
Options carry metadata similar to HTTP headers but use efficient binary encoding:
1221.8.1 Common Options
| Option Number | Name | Length | Purpose |
|---|---|---|---|
| 3 | Uri-Host | String | Target host |
| 7 | Uri-Port | 0-2 bytes | Target port |
| 11 | Uri-Path | String | Path segments (/sensors/temp) |
| 12 | Content-Format | 0-2 bytes | Payload MIME type |
| 14 | Max-Age | 0-4 bytes | Cacheability (seconds) |
| 17 | Accept | 0-2 bytes | Acceptable response format |
| 35 | Proxy-Uri | String | For proxied requests |
1221.8.2 Option Delta Encoding
Options are sorted by number and use delta encoding to minimize bytes:
Option format:
+----+----+----------------+----------------+
| OD | OL | [Extended OD] | Value |
+----+----+----------------+----------------+
4 4 0, 1, or 2 Variable
bits bits bytes
OD = Option Delta (difference from previous option number)
OL = Option Length
Example: Encoding Uri-Path /sensors/temp
Option 1: Uri-Path = "sensors"
Delta = 11 (first option, no previous)
Length = 7 ("sensors")
Encoded: 0xB7 | "sensors"
Option 2: Uri-Path = "temp"
Delta = 0 (11 - 11 = 0, same option type)
Length = 4 ("temp")
Encoded: 0x04 | "temp"
Total: 13 bytes vs HTTP "GET /sensors/temp HTTP/1.1\r\n" = 27 bytes
1221.8.3 Content-Format Codes
The Content-Format option specifies the payload MIME type:
| Code | MIME Type | Description |
|---|---|---|
| 0 | text/plain | Simple text |
| 40 | application/link-format | Resource discovery |
| 41 | application/xml | XML data |
| 42 | application/octet-stream | Binary data |
| 47 | application/exi | Efficient XML |
| 50 | application/json | JSON data |
| 60 | application/cbor | Compact Binary (CBOR) |
CBOR (Concise Binary Object Representation) is to JSON what CoAP is to HTTP - a compact binary alternative:
# JSON (42 bytes)
{"device":"temp42","value":23.5,"unit":"C"}
# CBOR (~20 bytes) - same data, half the size
A3 66 64 65 76 69 63 65 66 74 65 6D 70 34 32...When to use: - CBOR: Production deployments, battery-powered devices, constrained networks - JSON: Development, debugging, cloud integration with JSON-native APIs
1221.9 Worked Example: Parsing a CoAP Message
1221.10 Common Pitfalls
The Mistake: Implementing /.well-known/core resource discovery but returning plain JSON instead of the required CoRE Link Format (application/link-format, Content-Format 40), causing standard CoAP clients and gateways to reject the discovery response with 4.06 Not Acceptable.
Why It Happens: Developers familiar with REST APIs assume JSON is universal. However, RFC 6690 mandates that /.well-known/core responses use the CoRE Link Format media type (application/link-format), which has a specific syntax with angle brackets, semicolons, and comma-separated attributes.
The Fix: Return properly formatted CoRE Link Format with Content-Format option set to 40:
Incorrect (JSON - causes 4.06 Not Acceptable):
{"resources": [{"uri": "/temperature", "type": "sensor"}]}Correct (CoRE Link Format - Content-Format: 40):
</temperature>;rt="oic.r.temperature";if="oic.if.s";ct=50,
</humidity>;rt="oic.r.humidity";if="oic.if.s";ct=50,
</led>;rt="oic.r.switch.binary";if="oic.if.a";ct=50
Link Format attributes: - rt (resource type): Semantic type from IANA registry - if (interface): Interaction model (oic.if.s = sensor, oic.if.a = actuator) - ct (content-format): Payload format for resource (50 = application/json) - obs (observable): Present if resource supports Observe
Always test discovery with standard tools: coap-client -m get coap://device/.well-known/core should return parseable link format, not a 4.06 error.
The Mistake: Using Message ID for request-response correlation instead of Token, causing responses to be mismatched when multiple requests are in flight.
Why It Happens: Both fields look like “identifiers,” but they serve completely different purposes:
- Message ID: Transport-level, for ACK matching and deduplication. Changes on retransmission.
- Token: Application-level, for matching responses to requests. Same across retransmissions.
The Fix: Always use Token for correlating responses to requests:
# BAD: Using Message ID for correlation
pending_requests[message_id] = callback
# GOOD: Using Token for correlation
pending_requests[token] = callbackWhen you send a CON message and it times out, you retransmit with the SAME Message ID (so server can deduplicate) but the Token stays the same throughout, allowing proper response matching.
1221.11 Summary
The CoAP message format achieves remarkable efficiency:
- 4-byte fixed header encodes version, type, code, and message ID
- Tokens (0-8 bytes) correlate responses to requests
- Delta-encoded options minimize metadata overhead
- Response codes mirror HTTP semantics (2.xx success, 4.xx client error, 5.xx server error)
Understanding this format is essential for debugging network captures, implementing CoAP libraries, and optimizing message sizes for constrained networks.
1221.12 What’s Next
Now that you understand the message format:
- Reliability Patterns: CoAP Message Types - Learn when to use CON vs NON and how retransmission works
- Server Push: CoAP Observe Extension - Enable push notifications for real-time monitoring
- See All CoAP Topics: CoAP Fundamentals and Architecture - Complete chapter index