> ## Documentation Index
> Fetch the complete documentation index at: https://docs.noxpay.io/llms.txt
> Use this file to discover all available pages before exploring further.

# NaaS — Autenticação e Configuração

> Como autenticar como merchant master e assinar requisições para a API Noxpay as a Service (NaaS).

## O que é o NaaS?

O Noxpay as a Service (NaaS) permite que um **merchant master** opere contas de sub-merchants de forma programática. Usando sua chave de API master junto com uma assinatura criptográfica, você pode cadastrar sub-merchants, iniciar onboarding KYB, criar links de checkout, gerenciar carteiras, iniciar saques e consultar splits — tudo vinculado a um sub-merchant específico via `correlation_id`.

## URL base

```
https://checkout.noxpay.io
```

Todos os endpoints NaaS estão sob o prefixo `/v2/naas/`.

## Autenticação

Toda requisição NaaS exige o header `api-key`. O mecanismo de autenticação difere pelo método HTTP:

* Requisições **POST** carregam a autenticação no **corpo da requisição** como um envelope JSON assinado.
* Requisições **GET** carregam a autenticação inteiramente em **headers** — nenhum corpo é enviado.

### Requisições POST — envelope assinado

Todo corpo POST é um envelope JSON:

```json theme={null}
{
  "timestamp":      "2026-05-19T14:30:00Z",
  "correlation_id": "a1b2c3d4-e5f6-4789-abcd-000000000001",
  "payload":        {}
}
```

| Campo            | Tipo              | Descrição                                                                                                                                   |
| ---------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `timestamp`      | string (RFC 3339) | Hora atual em UTC. Requisições fora de ±1 minuto são rejeitadas.                                                                            |
| `correlation_id` | string (UUID)     | UUID do relacionamento master–sub-merchant. **Omitir completamente** para endpoints que operam no nível do master (consulte cada endpoint). |
| `payload`        | object            | Corpo específico do endpoint.                                                                                                               |

Serialize o envelope para bytes, calcule o SHA-256, assine com RSA PKCS#1 v1.5, codifique o resultado em Base64 e envie como `X-Signature`.

### Requisições GET — headers assinados

Endpoints GET não enviam corpo. Passe a autenticação em três headers adicionais:

| Header             | Descrição                                                                                                   |
| ------------------ | ----------------------------------------------------------------------------------------------------------- |
| `api-key`          | Sua chave de API do merchant master                                                                         |
| `X-Timestamp`      | Timestamp UTC no formato RFC 3339. Requisições fora de ±1 minuto são rejeitadas.                            |
| `X-Correlation-ID` | UUID do relacionamento master–sub-merchant.                                                                 |
| `X-Signature`      | Assinatura RSA-PKCS1v15-SHA256 da string canônica `<X-Timestamp>\n<X-Correlation-ID>`, codificada em Base64 |

Assine os bytes UTF-8 da string canônica: o valor exato de `X-Timestamp`, uma quebra de linha (`\n`), seguido do valor exato de `X-Correlation-ID`.

<Note>
  `GET /v2/naas/submerchants/onboarding_status` é o único endpoint GET que usa apenas `api-key` — não são necessários headers assinados.
</Note>

## Configuração de chave

### 1. Gerar um par de chaves RSA

A chave deve ter pelo menos 2048 bits. Recomendamos 4096 bits para chaves de longa duração.

```bash theme={null}
# Gerar chave privada de 4096 bits
openssl genrsa -out naas_private.pem 4096

# Extrair a chave pública
openssl rsa -in naas_private.pem -pubout -out naas_public.pem
```

O formato PKCS#1 de chave pública também é aceito:

```bash theme={null}
openssl rsa -in naas_private.pem -RSAPublicKey_out -out naas_public_pkcs1.pem
```

Mantenha `naas_private.pem` em seus servidores e nunca a compartilhe. Apenas a chave pública é registrada na Noxpay.

### 2. Registrar a chave pública

No painel da Noxpay, acesse **NaaS → Configuração → Chave Pública**, cole o conteúdo de `naas_public.pem` e salve. A chave entra em vigor imediatamente. Você pode rotacioná-la a qualquer momento — a chave anterior é desativada automaticamente.

### 3. Assinar requisições

#### POST — assinar o envelope

1. Monte o envelope JSON com o timestamp UTC atual, opcionalmente o `correlation_id`, e o payload do endpoint.
2. Serialize para bytes — não re-serialize após assinar.
3. Calcule o SHA-256 dos bytes.
4. Assine com sua chave privada RSA usando padding PKCS#1 v1.5.
5. Codifique o resultado em Base64 e envie como `X-Signature`.

<CodeGroup>
  ```go Go theme={null}
  import (
      "crypto"
      "crypto/rand"
      "crypto/rsa"
      "crypto/sha256"
      "crypto/x509"
      "encoding/base64"
      "encoding/json"
      "encoding/pem"
      "time"
  )

  func signEnvelope(privateKeyPEM []byte, correlationID string, payload any) (body []byte, sig string, err error) {
      block, _ := pem.Decode(privateKeyPEM)
      key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
      if err != nil {
          return nil, "", err
      }
      envelope := map[string]any{
          "timestamp": time.Now().UTC().Format(time.RFC3339),
          "payload":   payload,
      }
      if correlationID != "" {
          envelope["correlation_id"] = correlationID
      }
      body, err = json.Marshal(envelope)
      if err != nil {
          return nil, "", err
      }
      hash := sha256.Sum256(body)
      sigBytes, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, hash[:])
      if err != nil {
          return nil, "", err
      }
      return body, base64.StdEncoding.EncodeToString(sigBytes), nil
  }
  ```

  ```python Python theme={null}
  import base64, json, time
  from cryptography.hazmat.primitives import hashes, serialization
  from cryptography.hazmat.primitives.asymmetric import padding

  with open("naas_private.pem", "rb") as f:
      private_key = serialization.load_pem_private_key(f.read(), password=None)

  def sign_envelope(payload: dict, correlation_id: str = None) -> tuple[bytes, str]:
      envelope = {
          "timestamp": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
          "payload": payload,
      }
      if correlation_id:
          envelope["correlation_id"] = correlation_id
      body = json.dumps(envelope, separators=(",", ":")).encode()
      sig = private_key.sign(body, padding.PKCS1v15(), hashes.SHA256())
      return body, base64.b64encode(sig).decode()
  ```

  ```javascript Node.js theme={null}
  const crypto = require('crypto');
  const fs = require('fs');

  const privateKey = fs.readFileSync('naas_private.pem', 'utf8');

  function signEnvelope(payload, correlationId = null) {
    const envelope = {
      timestamp: new Date().toISOString().replace(/\.\d{3}Z$/, 'Z'),
      payload,
      ...(correlationId ? { correlation_id: correlationId } : {}),
    };
    const body = Buffer.from(JSON.stringify(envelope));
    const sig = crypto.sign('sha256', body, {
      key: privateKey,
      padding: crypto.constants.RSA_PKCS1_PADDING,
    });
    return { body, signature: sig.toString('base64') };
  }
  ```
</CodeGroup>

#### GET — assinar os headers

Monte a string canônica `<X-Timestamp>\n<X-Correlation-ID>`, assine o hash SHA-256 com sua chave RSA (PKCS#1 v1.5) e codifique o resultado em Base64 como `X-Signature`.

<CodeGroup>
  ```go Go theme={null}
  func signGETHeaders(privateKeyPEM []byte, correlationID string) (timestamp, sig string, err error) {
      block, _ := pem.Decode(privateKeyPEM)
      key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
      if err != nil {
          return "", "", err
      }
      timestamp = time.Now().UTC().Format(time.RFC3339)
      canonical := timestamp + "\n" + correlationID
      hash := sha256.Sum256([]byte(canonical))
      sigBytes, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, hash[:])
      if err != nil {
          return "", "", err
      }
      return timestamp, base64.StdEncoding.EncodeToString(sigBytes), nil
  }

  // Uso:
  // ts, sig, _ := signGETHeaders(privKeyPEM, correlationID)
  // req.Header.Set("X-Timestamp", ts)
  // req.Header.Set("X-Correlation-ID", correlationID)
  // req.Header.Set("X-Signature", sig)
  ```

  ```python Python theme={null}
  import base64, time
  from cryptography.hazmat.primitives import hashes
  from cryptography.hazmat.primitives.asymmetric import padding

  def sign_get_headers(private_key, correlation_id: str) -> dict:
      timestamp = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
      canonical = f"{timestamp}\n{correlation_id}".encode()
      sig = private_key.sign(canonical, padding.PKCS1v15(), hashes.SHA256())
      return {
          "X-Timestamp": timestamp,
          "X-Correlation-ID": correlation_id,
          "X-Signature": base64.b64encode(sig).decode(),
      }
  ```

  ```javascript Node.js theme={null}
  function signGETHeaders(correlationId) {
    const timestamp = new Date().toISOString().replace(/\.\d{3}Z$/, 'Z');
    const canonical = Buffer.from(`${timestamp}\n${correlationId}`);
    const sig = crypto.sign('sha256', canonical, {
      key: privateKey,
      padding: crypto.constants.RSA_PKCS1_PADDING,
    });
    return {
      'X-Timestamp': timestamp,
      'X-Correlation-ID': correlationId,
      'X-Signature': sig.toString('base64'),
    };
  }
  ```
</CodeGroup>

## Proteção contra replay

Cada combinação `(timestamp, correlation_id, signature)` é tratada como um token de uso único. Sempre use o horário atual ao montar o envelope ou assinar headers — nunca reutilize uma requisição previamente assinada.

## Verificação de webhook

Todos os webhooks do NaaS são assinados com HMAC-SHA256 usando seu segredo de webhook. A assinatura é entregue em dois headers:

| Header            | Formato        | Descrição                                            |
| ----------------- | -------------- | ---------------------------------------------------- |
| `X-Signature`     | string hex     | HMAC-SHA256 do corpo bruto da requisição             |
| `X-NOX-Signature` | `sha256=<hex>` | Mesmo digest com o prefixo `sha256=` (estilo GitHub) |

Verifique qualquer um dos headers — eles carregam o mesmo digest.

Registre seu segredo de webhook em **NaaS → Configuração → Segredo de Webhook**. O segredo deve ter entre 32 e 512 caracteres imprimíveis, sem espaços.

<CodeGroup>
  ```go Go theme={null}
  import (
      "crypto/hmac"
      "crypto/sha256"
      "encoding/hex"
  )

  func verifyWebhook(body []byte, secret, receivedSig string) bool {
      mac := hmac.New(sha256.New, []byte(secret))
      mac.Write(body)
      expected := hex.EncodeToString(mac.Sum(nil))
      return hmac.Equal([]byte(expected), []byte(receivedSig))
  }
  ```

  ```python Python theme={null}
  import hashlib, hmac

  def verify_webhook(body: bytes, secret: str, received_sig: str) -> bool:
      expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
      return hmac.compare_digest(expected, received_sig)
  ```
</CodeGroup>
