Stream Manager 2.0 Explicit Provisioning
Overview
This guide explains how to use explicit provisioning with Red5 Pro Stream Manager 2.0 autoscaling. Explicit provisioning gives you fine-grained control over where and how provisions are distributed to servers based on capabilities.
For more information about provisions in Stream Manager 2.0:
- ABR and Transcoding Migration Guide – ABR provision format and workflows
 - Restreamer Migration Guide – Restreamer provision format and parameters
 - Transcoder and ABR Overview – General transcoding concepts
 - Stream Manager 2.0 Streams Provision API – Complete API reference
 
What’s New: Explicit Distribution
Previously, provisions were distributed automatically when calling Get Server for Publish with specific flags (transcode=true, restream=true). The new workflow introduces:
- Separate 
/distributeendpoint – Explicitly distribute provisions to servers based on capabilities - Capability-based selection – Control exactly which node types receive provisions
 - Flexible workflows – Create provision → Distribute → Publish, or combine steps
 - Egress restreaming – Push restreamers to edge nodes instead of origin nodes
 
Key Concepts
Provision: A configuration that defines additional parameters for a stream (transcoding settings, ingest credentials, cloud storage, etc.)
Distribution: The act of sending a provision to one or more nodes so they can apply the configuration
Capabilities: Node role attributes that determine what functions a node can perform:
PUBLISH– Origin nodes that accept published streamsTRANSCODE– Transcoder nodes that create ABR variantsSUBSCRIBE– Edge nodes that serve subscribersMIX– Mixer nodes for conferencing
For more information about node roles and capabilities, see:
- NodeGroupConfig Examples Overview – Cluster topology examples showing different role configurations
 - Stream Manager 2.0 Admin API – Complete NodeGroupConfig and NodeRole specification
 
Three-Level Capability Precedence
When selecting servers for provision distribution, capabilities are determined using a three-level precedence system. This applies to both:
- The new 
/distributeendpoint - The traditional Get Server for Publish endpoint, when 
distribute=true(or unspecified;trueby default) 
This gives you flexible control over where provisions are distributed.
1. API Parameter Capabilities (Highest Priority)
If the API call includes an explicit capabilities parameter, those capabilities are used exclusively.
Example:
POST /as/v1/streams/provision/default/distribute/my-provision?capabilities=SUBSCRIBE
Use case: Override provision settings to push a restreamer to edge nodes instead of origin.
2. Provision Capabilities (Medium Priority)
If no API capabilities are provided, check if the provision itself has a capabilities field. If present and non-empty, use those capabilities.
Example provision:
{
  "provisionGuid": "my-provision",
  "capabilities": ["TRANSCODE","PUBLISH"],
  "streams": [...]
}
Use case: Provision declares it requires transcoding capability and an ingress (“PUBLISH”) node.
3. Implicit Capabilities (Lowest Priority/Fallback)
If neither API nor provision specify capabilities, derive them implicitly:
- If provision has 
videoParams→ ImplicitTRANSCODEcapability - If provision has 
camParams→ ImplicitPUBLISHcapability - Otherwise → Default 
PUBLISHcapability 
Example:
{
  "provisionGuid": "abr-provision",
  "streams": [
    {
      "streamGuid": "live/test_1",
      "videoParams": {"videoWidth": 1280, ...}
    }
  ]
}
This implicitly requires TRANSCODE capability because of videoParams.
Why This Matters
Flexibility: The precedence system allows you to:
- Create a provision with default capabilities
 - Override them per-distribution using the API parameter
 - Enable new use cases (like egress restreaming) without modifying existing provisions
 
Example – Egress Restreaming:
A restreamer provision normally goes to origin nodes (implicit PUBLISH). But you can override with ?capabilities=SUBSCRIBE to push it to edge nodes instead:
POST /as/v1/streams/provision/default/distribute/rtmp-push?capabilities=SUBSCRIBE
This is how egress restreaming works – the API parameter overrides the implicit behavior.
Workflow Comparison
Old Workflow (Implicit Distribution)
Simple case: ABR with transcoding
- Create ABR provision with videoParams
 - Get Server for Publish (implicitly distributes to origin + transcoder)
 - Publish to returned server (transcoder)
 
POST /as/v1/streams/provision/{nodeGroup}
GET /as/v1/streams/stream/{nodeGroup}/publish/{streamGuid}?transcode=true
Limitations:
- Distribution happens automatically during Get Server for Publish
 - Limited control over where provisions go (always origin + transcoder for 
transcode=true) - Restreamer provisions always go to origin/transcoder nodes (ingest restreaming only)
 - Cannot test distribution separately from publishing
 - Complex case: To use both 
transcode=trueANDrestream=true, you must create TWO separate provisions with differentprovisionGuidvalues, where the restreamer provision’sstreamGuidmatches the top-level ABR variant 
New Workflow (Explicit Distribution)
Simple case: ABR with transcoding
- Create ABR provision
 
POST /as/v1/streams/provision/{nodeGroup}
- Explicitly distribute provision to origin and transcoder
 
POST /as/v1/streams/provision/{nodeGroup}/distribute/{provisionGuid}?capabilities=PUBLISH,TRANSCODE
- Get Server for Publish (optionally skip distribution with 
distribute=false) 
GET /as/v1/streams/stream/{nodeGroup}/publish/{streamGuid}?distribute=false
- Publish to returned server (transcoder)
 
ffmpeg -stream_loop -1 -re -i testvideo.mp4 -c:v libx264 -profile:v baseline -c:a aac -b:v 500k -f flv rtmp://158.0.0.223:1935/live/test1_1
Benefits:
- Separate distribution from server selection
 - Precise control via capabilities parameter
 - Can push restreamers to edge nodes (egress restreaming) using 
capabilities=SUBSCRIBE - Easier testing and debugging
 - Same workflow works for both simple and complex cases
 
Authentication
All provision API calls require a valid JWT presented in the Authorization header as a bearer token:
export JWT="your-jwt-token-here"
curl -H "Authorization: Bearer ${JWT}" ...
See the Stream Manager 2.0 Auth API documentation for obtaining tokens.
Use Case 1: ABR Provision Without Transcoding
Scenario: Publish a stream with multiple ABR variants, all generated by the publisher (no server-side transcoding).
Provision Definition
abr-no-transcode.json
[
  {
    "provisionGuid": "abr-stream1",
    "streams": [
      {
        "streamGuid": "live/stream1_3",
        "abrLevel": 3,
        "videoParams": {
          "videoWidth": 320,
          "videoHeight": 180,
          "videoBitRate": 500000
        }
      },
      {
        "streamGuid": "live/stream1_2",
        "abrLevel": 2,
        "videoParams": {
          "videoWidth": 640,
          "videoHeight": 360,
          "videoBitRate": 1000000
        }
      },
      {
        "streamGuid": "live/stream1_1",
        "abrLevel": 1,
        "videoParams": {
          "videoWidth": 1280,
          "videoHeight": 720,
          "videoBitRate": 2000000
        }
      }
    ]
  }
]
Workflow Steps
1. Create Provision
curl -H "Content-Type: application/json" 
     -H "Authorization: Bearer ${JWT}" 
     -X POST 
     --data @abr-no-transcode.json 
     https://streammanager.example.com/as/v1/streams/provision/default
2. Distribute to Origin Node (Explicit)
curl -H "Authorization: Bearer ${JWT}" 
     -X POST 
     "https://streammanager.example.com/as/v1/streams/provision/default/distribute/abr-stream1?capabilities=PUBLISH&endpoints=1&blocking=true"
Response:
[
  {
    "streamGuid": "live/stream1_1",
    "serverAddress": "192.168.1.10",
    "nodeRole": "origin",
    "nodeState": "INSERVICE",
    "subGroup": "us-east"
  }
]
3. Get Server for Publish (Skip Distribution)
curl "https://streammanager.example.com/as/v1/streams/stream/default/publish/live/stream1_1?distribute=false"
Response: Same as step 2 (provision already distributed)
4. Publish All Variants
Use Red5 Pro SDK or RTMP encoder to publish all three variants to the returned server:
live/stream1_1(1280×720, 2 Mbps)live/stream1_2(640×360, 1 Mbps)live/stream1_3(320×180, 500 Kbps)
5. Verify Streams
curl -H "Authorization: Bearer ${JWT}" 
     "https://streammanager.example.com/as/v1/streams/stream/default?stats=true"
6. Subscribe
Get edge server for any variant:
curl "https://streammanager.example.com/as/v1/streams/stream/default/subscribe/live/stream1_1"
Use Case 2: ABR Provision With Transcoding
Scenario: Publish one high-quality stream, let the server transcode it into multiple ABR variants.
Provision Definition
abr-transcode.json
[
  {
    "provisionGuid": "abr-transcode1",
    "capabilities": ["TRANSCODE"],
    "streams": [
      {
        "streamGuid": "live/mystream_3",
        "abrLevel": 3,
        "videoParams": {
          "videoWidth": 320,
          "videoHeight": 180,
          "videoBitRate": 500000
        }
      },
      {
        "streamGuid": "live/mystream_2",
        "abrLevel": 2,
        "videoParams": {
          "videoWidth": 640,
          "videoHeight": 360,
          "videoBitRate": 1000000
        }
      },
      {
        "streamGuid": "live/mystream_1",
        "abrLevel": 1,
        "videoParams": {
          "videoWidth": 1280,
          "videoHeight": 720,
          "videoBitRate": 2000000
        }
      }
    ]
  }
]
Workflow Steps
1. Create Provision
curl -H "Content-Type: application/json" 
     -H "Authorization: Bearer ${JWT}" 
     -X POST 
     --data @abr-transcode.json 
     https://streammanager.example.com/as/v1/streams/provision/default
2. Distribute to Origin AND Transcoder (Explicit)
curl -H "Authorization: Bearer ${JWT}" 
     -X POST 
     "https://streammanager.example.com/as/v1/streams/provision/default/distribute/abr-transcode1?capabilities=PUBLISH,TRANSCODE&endpoints=1&blocking=true"
Response:
[
  {
    "streamGuid": "live/mystream_1",
    "serverAddress": "192.168.1.20",
    "nodeRole": "transcoder",
    "nodeState": "INSERVICE",
    "subGroup": "us-east"
  },
  {
    "streamGuid": "live/mystream_1",
    "serverAddress": "192.168.1.10",
    "nodeRole": "origin",
    "nodeState": "INSERVICE",
    "subGroup": "us-east"
  }
]
Note: The transcoder is listed first – this is where you should publish.
3. Get Server for Publish (Combined Approach)
Alternatively, use the traditional approach with transcode=true:
curl "https://streammanager.example.com/as/v1/streams/stream/default/publish/live/mystream_1?transcode=true&distribute=true"
This both selects servers and distributes the provision in one call.
4. Publish to Transcoder
Publish only live/mystream_1 to the transcoder address (first result).
The transcoder will:
- Receive your high-quality stream
 - Transcode it into all three variants
 - Forward all variants to the origin
 
5. Verify All Variants Exist
curl -H "Authorization: Bearer ${JWT}" 
     "https://streammanager.example.com/as/v1/streams/stream/default/live/mystream_1?stats=true"
You should see three streams (mystream_1, mystream_2, mystream_3) all on the origin node.
Use Case 3: Ingest Restreamer (SRT/RTSP/IP Camera)
Scenario: Ingest a stream from an external source (SRT listener, RTSP camera, MPEG-TS) onto an origin node.
Provision Definition
ingest-srt-persist.json
[
  {
    "provisionGuid": "srt-camera1",
    "streams": [
      {
        "streamGuid": "live/camera1",
        "abrLevel": 0,
        "camParams": {
          "properties": {
            "action": "create",
            "type": "srt",
            "ip": "0.0.0.0",
            "port": "9000",
            "frameType": 0,
            "latency": 120,
            "reorder": 16,
            "overhead": 100,
            "keyLength": 0,
            "unlinkClock": false,
            "audio": true,
            "video": true,
            "persist": "true"
          }
        }
      }
    ]
  }
]
Parameters Explained:
type: "srt"– SRT listener mode (other options:rtsp,mpegts,zixi-push,zixi-pull)persist: "true"– If the stream goes away, automatically retry/redistributeport: "9000"– Listen on port 9000 for incoming SRT connection
Workflow Steps
1. Create Provision
curl -H "Content-Type: application/json" 
     -H "Authorization: Bearer ${JWT}" 
     -X POST 
     --data @ingest-srt-persist.json 
     https://streammanager.example.com/as/v1/streams/provision/default
2. Distribute to Origin Node
curl -H "Authorization: Bearer ${JWT}" 
     -X POST 
     "https://streammanager.example.com/as/v1/streams/provision/default/distribute/srt-camera1?capabilities=PUBLISH&blocking=true"
Response:
[
  {
    "streamGuid": "live/camera1",
    "serverAddress": "192.168.1.10",
    "nodeRole": "origin",
    "nodeState": "INSERVICE",
    "subGroup": "us-east"
  }
]
3. Get Server for Publish (Alternative)
curl "https://streammanager.example.com/as/v1/streams/stream/default/publish/live/camera1?restream=true"
This combines steps 2-3 using the implicit distribution approach.
4. Send SRT Stream to Origin
From your camera or encoder, send SRT stream to srt://192.168.1.10:9000:
ffmpeg -f lavfi -re -i testsrc=size=1280x720:rate=30 
       -f lavfi -re -i sine=frequency=1000:sample_rate=44100 
       -pix_fmt yuv420p -c:v libx264 -b:v 2000k 
       -c:a aac -b:a 128k 
       -f mpegts "srt://192.168.1.10:9000?pkt_size=1316"
5. Verify Stream is LIVE
curl -H "Authorization: Bearer ${JWT}" 
     "https://streammanager.example.com/as/v1/streams/stream/default/live/camera1?stats=true"
Expected state: "state": "LIVE"
6. Subscribe
curl "https://streammanager.example.com/as/v1/streams/stream/default/subscribe/live/camera1"
7. Stream Stops – Automatic Recovery
If the SRT source disconnects and then reconnects, the persist: "true" flag ensures the restreamer automatically retries and the stream comes back without manual intervention.
Use Case 4: Combined ABR + Restreamer (Ingest with Transcoding)
Scenario: Ingest from an IP camera and transcode into multiple variants.
Provisions
Create two separate provisions:
ingest-camera.json (Restreamer)
[
  {
    "provisionGuid": "camera-ingest",
    "streams": [
      {
        "streamGuid": "live/camera1",
        "abrLevel": 0,
        "camParams": {
          "properties": {
            "action": "create",
            "type": "rtsp",
            "rtspUri": "rtsp://192.168.100.50:554/stream",
            "immediate": "true",
            "persist": "true"
          }
        }
      }
    ]
  }
]
transcode-camera.json (ABR Transcoding)
[
  {
    "provisionGuid": "camera-abr",
    "capabilities": ["TRANSCODE"],
    "streams": [
      {
        "streamGuid": "live/camera1_3",
        "abrLevel": 3,
        "videoParams": {
          "videoWidth": 320,
          "videoHeight": 180,
          "videoBitRate": 500000
        }
      },
      {
        "streamGuid": "live/camera1_2",
        "abrLevel": 2,
        "videoParams": {
          "videoWidth": 640,
          "videoHeight": 360,
          "videoBitRate": 1000000
        }
      },
      {
        "streamGuid": "live/camera1_1",
        "abrLevel": 1,
        "videoParams": {
          "videoWidth": 1280,
          "videoHeight": 720,
          "videoBitRate": 2000000
        }
      }
    ]
  }
]
Workflow Steps
1. Create Both Provisions
curl -H "Content-Type: application/json" -H "Authorization: Bearer ${JWT}" 
     -X POST --data @ingest-camera.json 
     https://streammanager.example.com/as/v1/streams/provision/default
curl -H "Content-Type: application/json" -H "Authorization: Bearer ${JWT}" 
     -X POST --data @transcode-camera.json 
     https://streammanager.example.com/as/v1/streams/provision/default
2. Distribute Restreamer to Origin
curl -H "Authorization: Bearer ${JWT}" -X POST 
     "https://streammanager.example.com/as/v1/streams/provision/default/distribute/camera-ingest?capabilities=PUBLISH&blocking=true"
The origin node immediately begins ingesting from the RTSP camera.
3. Distribute ABR to Origin and Transcoder
curl -H "Authorization: Bearer ${JWT}" -X POST 
     "https://streammanager.example.com/as/v1/streams/provision/default/distribute/camera-abr?capabilities=PUBLISH,TRANSCODE&blocking=true"
The transcoder pulls live/camera1 from the origin and begins creating variants.
4. Verify All Streams
curl -H "Authorization: Bearer ${JWT}" 
     "https://streammanager.example.com/as/v1/streams/stream/default?stats=false"
You should see camera1, camera1_1, camera1_2, camera1_3.
Use Case 5: Egress Restreamer (RTMP Push to Social Media)
Scenario: Push a live stream to a social media platform (YouTube, Facebook, custom RTMP) from an edge node to avoid loading the origin.
Why Egress Restreaming?
Traditional (Old) Workflow:
- Restreamer provisions always go to origin/transcoder nodes (using 
PUBLISHorTRANSCODEcapability) - Origin node must both serve the stream AND push to social media
 - Increases origin load
 
New Egress Workflow:
- Set 
capabilities: ["SUBSCRIBE"]to push restreamer to an edge node - Edge node subscribes to the stream and pushes to social media
 - Origin only serves the stream, egress load is offloaded to edge
 
Provision Definition
egress-rtmp-youtube.json
[
  {
    "provisionGuid": "social-youtube",
    "capabilities": ["SUBSCRIBE"],
    "streams": [
      {
        "streamGuid": "live/mystream",
        "abrLevel": 0,
        "camParams": {
          "properties": {
            "action": "create",
            "type": "rtmp-push",
            "rtmpUri": "rtmp://a.rtmp.youtube.com/live2/your-stream-key-here",
            "immediate": "false",
            "attempts": "3",
            "delayS": "10",
            "persist": "true"
          }
        }
      }
    ]
  }
]
Parameters Explained:
capabilities: ["SUBSCRIBE"]– Key change! Pushes restreamer to edge nodetype: "rtmp-push"– Push mode (forwards stream to external RTMP server)immediate: "false"– Wait for source stream to be live before attempting pushattempts: "3"– Try up to 3 times if push failsdelayS: "10"– Wait 10 seconds between retriespersist: "true"– If stream stops and restarts, automatically resume push
Workflow Steps (Old Way – Ingest Restreamer)
For comparison, the old workflow for RTMP push:
# Create provision
curl -H "Content-Type: application/json" -H "Authorization: Bearer ${JWT}" 
     -X POST --data @old-rtmp-push.json 
     https://streammanager.example.com/as/v1/streams/provision/default
# Get Server for Publish distributes restreamer to ORIGIN
curl "https://streammanager.example.com/as/v1/streams/stream/default/publish/live/mystream?restream=true"
# Publish to origin (origin pushes to YouTube)
Problem: Origin node handles both publishing and RTMP push.
Workflow Steps (New Way – Egress Restreamer)
1. Start Publishing First
# Get origin server
curl "https://streammanager.example.com/as/v1/streams/stream/default/publish/live/mystream"
# Publish to origin (normal workflow, no restreaming yet)
2. Create Egress Provision
curl -H "Content-Type: application/json" 
     -H "Authorization: Bearer ${JWT}" 
     -X POST 
     --data @egress-rtmp-youtube.json 
     https://streammanager.example.com/as/v1/streams/provision/default
3. Distribute to Edge Node (Egress)
curl -H "Authorization: Bearer ${JWT}" 
     -X POST 
     "https://streammanager.example.com/as/v1/streams/provision/default/distribute/social-youtube?capabilities=SUBSCRIBE&blocking=true"
Response:
[
  {
    "streamGuid": "live/mystream",
    "serverAddress": "192.168.1.30",
    "nodeRole": "edge",
    "nodeState": "INSERVICE",
    "subGroup": "us-west"
  }
]
What Happens:
- Provision distributed to edge node (not origin!)
 - Edge node subscribes to 
live/mystreamfrom origin - Edge node pushes received stream to YouTube RTMP server
 - Origin continues serving stream normally
 
4. Stream Stops and Restarts
If you stop publishing and restart, the persist: "true" flag ensures:
- Edge detects stream came back online
 - RTMP push automatically resumes
 - No manual intervention needed
 
5. Delete Provision (Stop Push)
curl -H "Authorization: Bearer ${JWT}" 
     -X DELETE 
     "https://streammanager.example.com/as/v1/streams/provision/default/social-youtube"
The edge node stops pushing to YouTube.
API Reference Summary
Create Provision
Endpoint: POST /as/v1/streams/provision/{nodeGroupName}
Request Body: Array of ProvisionRequest objects
Response: 201 Created
See Stream Manager 2.0 Streams Provision API for complete schema.
Distribute Provision
Endpoint: POST /as/v1/streams/provision/{nodeGroupName}/distribute/{provisionGuid}
Query Parameters:
| Parameter | Type | Required | Default | Description | 
|---|---|---|---|---|
capabilities | 
Set | 
No | (inferred) | Comma-separated capabilities: PUBLISH, TRANSCODE, SUBSCRIBE, MIX, ZIXI, XILINX | 
strict | 
Boolean | No | false | 
If true, require exact subgroup match | 
subgroup | 
String | No | null | Preferred subgroup/region | 
endpoints | 
Integer | No | 1 | 
Number of nodes to select | 
blocking | 
Boolean | No | true | 
Wait for distribution to complete | 
Capability Precedence:
- API parameter (highest priority) – 
?capabilities=SUBSCRIBE - Provision capabilities – 
"capabilities": ["TRANSCODE"]in provision JSON - Implicit capabilities (lowest priority):
- If provision has 
videoParams→TRANSCODE - If provision has 
camParams→PUBLISH - Otherwise → 
PUBLISH 
 - If provision has 
 
Response: 200 OK with array of StreamLocation objects
Example:
curl -H "Authorization: Bearer ${JWT}" -X POST 
     "https://streammanager.example.com/as/v1/streams/provision/default/distribute/my-provision?capabilities=PUBLISH,TRANSCODE&endpoints=1&blocking=true"
Get Server for Publish (Enhanced)
Endpoint: GET /as/v1/streams/stream/{nodeGroupName}/publish/{streamGuid}
Query Parameters:
| Parameter | Type | Required | Default | Description | 
|---|---|---|---|---|
distribute | 
Boolean | No | true | 
New! Set to false to skip provision distribution | 
transcode | 
Boolean | No | false | 
Request transcoder node (implies distribution) | 
restream | 
Boolean | No | false | 
Request restreamer provision (implies distribution) | 
strict | 
Boolean | No | false | 
Require exact subgroup match | 
subgroup | 
String | No | null | Preferred subgroup/region | 
endpoints | 
Integer | No | 1 | 
Number of origin nodes | 
New Behavior:
distribute=false– Only selects servers, does not distribute provision. Use this after calling/distributeexplicitly.distribute=true(default) – Selects servers AND distributes provision (old behavior, still supported).
Example (Skip Distribution):
# 1. Distribute explicitly
curl -H "Authorization: Bearer ${JWT}" -X POST 
     "https://streammanager.example.com/as/v1/streams/provision/default/distribute/my-provision?capabilities=PUBLISH"
# 2. Get server without redistributing
curl "https://streammanager.example.com/as/v1/streams/stream/default/publish/live/mystream?distribute=false"
Delete Provision
Endpoint: DELETE /as/v1/streams/provision/{nodeGroupName}/{provisionGuid}
Deletes the provision and kills any active restreamers on nodes.
Example:
curl -H "Authorization: Bearer ${JWT}" -X DELETE 
     "https://streammanager.example.com/as/v1/streams/provision/default/my-provision"
Best Practices
1. Use Explicit Distribution for Testing
Separate distribution from publishing when testing:
# Test distribution
curl -X POST ".../distribute/my-provision?capabilities=PUBLISH"
# Verify it worked
curl ".../provision/default/my-provision?status=true"
# Then publish
curl ".../publish/live/mystream?distribute=false"
2. Egress Restreaming for Scale
For RTMP push (social media, CDN), always use egress restreaming:
{
  "capabilities": ["SUBSCRIBE"],
  "streams": [{
    "camParams": {
      "properties": {
        "type": "rtmp-push",
        "rtmpUri": "rtmp://..."
      }
    }
  }]
}
This offloads push to edge nodes.
3. Persist for Reliability
Always use "persist": "true" for production restreamers (ingest and egress):
"camParams": {
  "properties": {
    "persist": "true"
  }
}
The Stream Manager will automatically retry/redistribute if the stream goes away.
4. Immediate Flag for Ingest
For ingest restreamers, use "immediate": "true" when the source is already streaming:
"camParams": {
  "properties": {
    "type": "rtsp",
    "rtspUri": "rtsp://camera.local/stream",
    "immediate": "true"
  }
}
For egress/push, use "immediate": "false" to wait for the source stream.
5. Retry Configuration
For unreliable networks, configure retries:
"camParams": {
  "properties": {
    "attempts": "20",
    "delayS": "15"
  }
}
This gives 20 attempts × 15 seconds = 5 minutes of retry time.
Troubleshooting
Provision Not Distributing
Symptom: /distribute returns success but nodes don’t show the provision.
Check:
- Verify node roles have the requested capabilities in nodegroup config
 - Check node capacity – nodes over capacity are skipped
 - Verify nodes are in 
INSERVICEstate:GET /as/v1/streams/stream/debug/nodes - Check Stream Manager logs for errors
 
Restreamer Not Starting
Symptom: Provision distributed but restreamer doesn’t activate.
Check:
- Check node logs at 
/usr/local/red5pro/log/red5.log - For ingest: verify source is reachable from node
 - For egress: verify source stream is LIVE before restreamer attempts
 
Stream State is WAIT Instead of LIVE
When a restreamer is provisioned but the source stream doesn’t exist yet, the state shows WAIT. This is expected – once the source appears or restarts, the restreamer will activate and state becomes LIVE.
Capability Confusion
Symptom: Wrong nodes selected for distribution.
Remember the precedence:
- API 
?capabilities=parameter (overrides everything) - Provision 
"capabilities": [...]field - Implicit (inferred from 
videoParams/camParams) 
Use explicit API parameter to override: ?capabilities=SUBSCRIBE
Migration from Old to New Workflow
For Ingest (RTSP, SRT, IP Cameras)
Old:
curl -X POST --data @provision.json .../provision/default
curl ".../publish/live/camera1?restream=true"
New (equivalent):
curl -X POST --data @provision.json .../provision/default
curl -X POST ".../distribute/camera-provision?capabilities=PUBLISH"
New (explicit):
curl -X POST --data @provision.json .../provision/default
curl -X POST ".../distribute/camera-provision?capabilities=PUBLISH"
curl ".../publish/live/camera1?distribute=false"
For RTMP Push (Social Media)
Old (ingest restreamer on origin):
{
  "provisionGuid": "social1",
  "streams": [{
    "streamGuid": "live/mystream",
    "camParams": { "properties": { "type": "rtmp-push", "rtmpUri": "..." } }
  }]
}
curl ".../publish/live/mystream?restream=true"
New (egress restreamer on edge):
{
  "provisionGuid": "social1",
  "capabilities": ["SUBSCRIBE"],
  "streams": [{
    "streamGuid": "live/mystream",
    "camParams": { "properties": { "type": "rtmp-push", "rtmpUri": "..." } }
  }]
}
curl ".../publish/live/mystream"  # No restream flag
curl -X POST ".../distribute/social1?capabilities=SUBSCRIBE"
Summary
Explicit provisioning gives you:
✅ Separation of concerns – Create, distribute, and publish as independent steps
✅ Capability-based control – Choose exactly which node types receive provisions
✅ Egress restreaming – Offload RTMP push to edge nodes using SUBSCRIBE capability
✅ Easier testing – Test distribution separately from publishing
✅ Backward compatibility – Old implicit workflow still works
Key Takeaways:
- Use 
POST /as/v1/streams/provision/{nodeGroup}/distribute/{provisionGuid}for explicit distribution - Set 
?capabilities=SUBSCRIBEfor egress restreaming (RTMP push to social media) - Use 
?distribute=falsein Get Server for Publish to skip redistribution - Always use 
"persist": "true"for production restreamers - API capabilities parameter overrides provision capabilities
 
For more details on provision schemas, see Stream Manager 2.0 Streams Provision API.