Skip to main content

API Overview

This section provides comprehensive documentation for the NuNet Device Management Service API.

Server Configuration​

The REST server by default binds to 127.0.0.1 on port 9999. The configuration can be changed via the dms_config.json file using the rest.port and rest.addr parameters.

All API endpoints are accessed using the following base URL format:

http://<host>:<port>/api/v1/<endpoint>

API Endpoints​

Health and Configuration​

Health Check​

GET /health

Returns the health status of the API server.

Response:

{
"status": "ok"
}

Status Codes:

  • 200 OK: Server is healthy

Get Configuration​

GET /config

Returns the DMS configuration. This endpoint is only available when the server is running in debug mode.

Response (Debug Mode):

{
"config": {
// Full DMS configuration object
}
}

Response (Non-Debug Mode):

{
"config": "allowed in debug mode"
}

Status Codes:

  • 200 OK: Configuration returned successfully

Actor Management​

The Device Management Service uses an actor-based architecture for message passing and distributed communication. All actor endpoints are under /api/v1/actor.

Get Actor Handle​

GET /api/v1/actor/handle

Retrieves the actor handle for the DMS node, containing the actor ID, DID (Decentralized Identifier), and network address information.

Response:

{
"id": "actor-id-string",
"did": "did:key:...",
"addr": {
"host": "12D3KooW...",
"inbox": "root"
}
}

Status Codes:

  • 200 OK: Actor handle retrieved successfully
  • 500 Internal Server Error: Host node hasn't been initialized yet
  • 500 Internal Server Error: Handle ID is invalid

Send Message to Actor​

POST /api/v1/actor/send

Sends a message to a specific actor without waiting for a response (fire-and-forget).

Request Body:

{
"to": {
"id": "destination-actor-id",
"did": "did:key:...",
"addr": {
"host": "12D3KooW...",
"inbox": "target-inbox"
}
},
"be": "/dms/node/peers/ping",
"from": {
"id": "source-actor-id",
"did": "did:key:...",
"addr": {
"host": "12D3KooW...",
"inbox": "root"
}
},
"nonce": 1234567890,
"opt": {
"exp": 1642248000000000000,
"topic": "/nunet/hello"
},
"msg": "base64-encoded-message-bytes",
"cap": "base64-encoded-capability-token",
"sig": "base64-encoded-signature"
}

Response:

{
"message": "message sent"
}

Status Codes:

  • 200 OK: Message sent successfully
  • 400 Bad Request: Invalid request data
  • 500 Internal Server Error: Host node hasn't been initialized yet
  • 500 Internal Server Error: Failed to marshal message
  • 500 Internal Server Error: Destination address can't be resolved
  • 500 Internal Server Error: Failed to send message to destination

Invoke Actor Behavior​

POST /api/v1/actor/invoke

Invokes a behavior on an actor and waits for a response. This is a synchronous request-response pattern.

Request Body:

{
"to": {
"id": "destination-actor-id",
"did": "did:key:...",
"addr": {
"host": "12D3KooW...",
"inbox": "target-inbox"
}
},
"be": "/dms/node/peers/ping",
"from": {
"id": "source-actor-id",
"did": "did:key:...",
"addr": {
"host": "12D3KooW...",
"inbox": "root"
}
},
"nonce": 1234567890,
"opt": {
"exp": 1642248000000000000,
"cont": "/dms/actor/replyto/1234567890"
},
"msg": "base64-encoded-message-bytes",
"cap": "base64-encoded-capability-token",
"sig": "base64-encoded-signature"
}

Response: Returns an enveloped response message in the same format as the request:

{
"to": { ... },
"be": "/dms/actor/replyto/1234567890",
"from": { ... },
"nonce": 9876543210,
"opt": { ... },
"msg": "base64-encoded-response-bytes",
"cap": "base64-encoded-capability-token",
"sig": "base64-encoded-signature"
}

Status Codes:

  • 200 OK: Invocation successful, response returned
  • 400 Bad Request: Invalid request data
  • 408 Request Timeout: Request timed out waiting for response
  • 500 Internal Server Error: Host node hasn't been initialized yet
  • 500 Internal Server Error: Failed to marshal message
  • 500 Internal Server Error: Destination address can't be resolved
  • 500 Internal Server Error: Failed to send message to destination

Broadcast Message​

POST /api/v1/actor/broadcast

Broadcasts a message to a pubsub topic. All actors subscribed to the topic will receive the message and can respond.

Request Body:

{
"to": {},
"be": "/broadcast/hello",
"from": {
"id": "source-actor-id",
"did": "did:key:...",
"addr": {
"host": "12D3KooW...",
"inbox": "root"
}
},
"nonce": 1234567890,
"opt": {
"exp": 1642248000000000000,
"topic": "/nunet/hello"
},
"msg": "base64-encoded-message-bytes",
"cap": "base64-encoded-capability-token",
"sig": "base64-encoded-signature"
}

Response: Returns an array of response envelopes from actors that responded:

[
{
"to": { ... },
"be": "/dms/actor/replyto/1234567890",
"from": { ... },
"nonce": 9876543210,
"opt": { ... },
"msg": "base64-encoded-response-bytes",
"cap": "base64-encoded-capability-token",
"sig": "base64-encoded-signature"
}
]

Status Codes:

  • 200 OK: Broadcast successful, responses collected
  • 400 Bad Request: Invalid request data or message is not a broadcast message
  • 500 Internal Server Error: Host node hasn't been initialized yet
  • 500 Internal Server Error: Failed to marshal message
  • 500 Internal Server Error: Failed to publish message

Message Envelope Structure​

All actor messages use a standard envelope format:

Envelope Fields​

  • to (Handle, required): The destination actor's handle
  • be (string, required): The behavior/endpoint to invoke
  • from (Handle, required): The source actor's handle
  • nonce (uint64, required): A unique nonce for the message
  • opt (EnvelopeOptions, required): Options for message processing
  • msg ([]byte, required): The message payload as base64-encoded bytes
  • cap ([]byte, optional): Capability token for authorization
  • sig ([]byte, optional): Cryptographic signature for message verification

Handle Structure​

  • id (string): Actor identifier
  • did (string): Decentralized Identifier
  • addr (Address): Network address information
    • host (string): LibP2P peer ID
    • inbox (string): Inbox address for message routing

EnvelopeOptions Structure​

  • exp (uint64): Expiration timestamp in nanoseconds since Unix epoch
  • cont (string, optional): Reply-to continuation/behavior name (required for invoke)
  • topic (string, optional): Pubsub topic for broadcast messages (required for broadcast)

Error Handling​

The API uses standard HTTP status codes and returns error details in JSON format.

Error Response Format​

{
"error": "error message describing what went wrong"
}

Common Error Codes​

  • 400 Bad Request: Invalid request format or parameters
  • 408 Request Timeout: Request timed out (invoke/broadcast only)
  • 500 Internal Server Error: Server error (host not initialized, message send failure, etc.)

CORS Configuration​

The API server is configured with CORS support. The default configuration allows:

  • Origins: http://localhost:9991, http://localhost:9992
  • Methods: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS
  • Headers: Access-Control-Allow-Origin, Origin, Content-Length, Content-Type
  • Credentials: Not allowed
  • Max Age: 12 hours

Security Note: The current CORS configuration allowing localhost origins is a security risk and should be configured appropriately for production environments.

Client Library​

A Go client library is available for interacting with the DMS API. The client is part of the device-management-service repository.

Go Client Example​

package main

import (
"context"
"fmt"
"log"
"time"

"gitlab.com/nunet/device-management-service/client"
"gitlab.com/nunet/device-management-service/actor"
)

func main() {
// Create client configuration
cfg := client.Config{
Host: "localhost:9999",
Protocol: client.ConnectionTCP,
APIPrefix: "/api/v1",
Version: "v1",
}

// Create security context (required for actor operations)
securityCtx, err := client.NewClientSecurityContext(privateKeyReader, capabilityReader)
if err != nil {
log.Fatal(err)
}

// Create client
cli, err := client.NewClient(cfg, securityCtx)
if err != nil {
log.Fatal(err)
}

// Get DMS handle
handle, err := cli.GetDMSHandle(context.Background())
if err != nil {
log.Fatal(err)
}

fmt.Printf("DMS Handle: %+v\n", handle)

// Send a message
result, err := cli.SendMessage(
context.Background(),
"/dms/node/peers/ping",
map[string]interface{}{"ping": "pong"},
client.WithTimeout(30*time.Second),
)
if err != nil {
log.Fatal(err)
}

fmt.Printf("Message sent: %+v\n", result)
}

For more information about available behaviors and capabilities, see Code Reference.

Next Steps​