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