Authorization headers

TAPI v3 supports authentication via the Authorization header as an alternative to including credentials in the request body. This guide explains how to implement Authorization header authentication for your TAPI integrations.

Benefits of Authorization Header

  • Improved Security: Credentials are separated from business data, reducing accidental exposure when sharing request examples
  • Cleaner Request Bodies: Keep your request payloads focused on business logic only
  • Industry Standard: Aligns with REST API best practices
  • Debugging Safety: Share request bodies with team members without worrying about credential exposure

Authorization Header

Required Header Format

TAPI uses the standard Authorization header with a Bearer token format:

HeaderFormatExample
AuthorizationBearer {clientID}:{apiKey}Authorization: Bearer NC12345:sk_live_abc123xyz789

Important Notes

  • The format is Bearer followed by a space, then clientID:apiKey separated by a colon
  • Header names are case-insensitive (per HTTP specification)
  • The Authorization header takes precedence over body parameters if both are provided
  • The Bearer token must contain both clientID and apiKey separated by a colon (:)
  • GET endpoints REQUIRE the Authorization header - credentials cannot be passed in URL parameters

Migration Guide

Before (Body Authentication)

{
  "developerAPIKey": "sk_live_abc123xyz789",
  "clientID": "NC12345",
  "accountId": "A12345",
  "amount": 1000
}

After (Authorization Header)

Headers:

Authorization: Bearer NC12345:sk_live_abc123xyz789
Content-Type: application/json

Body:

{
  "accountId": "A12345",
  "amount": 1000
}

GET Endpoints (Authorization Header Required)

For GET endpoints, authentication MUST be provided via the Authorization header since there's no request body:

# GET endpoints require Authorization header
curl -X GET https://api-sandboxdash.norcapsecurities.com/tapiv3/parties \
  -H "Authorization: Bearer NC12345:sk_live_abc123xyz789"

# These endpoints include: parties, entities, trades, offerings, issuers, links, exports, jobs, permissions

Implementation Examples

cURL

curl -X POST https://api-sandboxdash.norcapsecurities.com/tapiv3/createTrade \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer NC12345:sk_live_abc123xyz789" \
  -d '{
    "accountId": "A12345",
    "offeringId": "O54321",
    "units": 100
  }'

JavaScript (Fetch API)

const response = await fetch('https://api-sandboxdash.norcapsecurities.com/tapiv3/createTrade', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer NC12345:sk_live_abc123xyz789'
  },
  body: JSON.stringify({
    accountId: 'A12345',
    offeringId: 'O54321',
    units: 100
  })
});

JavaScript (Axios)

const axios = require('axios');

const response = await axios.post(
  'https://api-sandboxdash.norcapsecurities.com/tapiv3/createTrade',
  {
    accountId: 'A12345',
    offeringId: 'O54321',
    units: 100
  },
  {
    headers: {
      'Authorization': 'Bearer NC12345:sk_live_abc123xyz789'
    }
  }
);

Python (Requests)

import requests

headers = {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer NC12345:sk_live_abc123xyz789'
}

data = {
    'accountId': 'A12345',
    'offeringId': 'O54321',
    'units': 100
}

response = requests.post(
    'https://api-sandboxdash.norcapsecurities.com/tapiv3/createTrade',
    headers=headers,
    json=data
)

PHP (cURL)

$ch = curl_init('https://api-sandboxdash.norcapsecurities.com/tapiv3/createTrade');

$headers = [
    'Content-Type: application/json',
    'Authorization: Bearer NC12345:sk_live_abc123xyz789'
];

$data = [
    'accountId' => 'A12345',
    'offeringId' => 'O54321',
    'units' => 100
];

curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

C# (.NET HttpClient)

using System.Net.Http;
using System.Text;
using System.Text.Json;

var client = new HttpClient();

client.DefaultRequestHeaders.Add("Authorization", "Bearer NC12345:sk_live_abc123xyz789");

var data = new
{
    accountId = "A12345",
    offeringId = "O54321",
    units = 100
};

var json = JsonSerializer.Serialize(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");

var response = await client.PostAsync(
    "https://api-sandboxdash.norcapsecurities.com/tapiv3/createTrade",
    content
);

Java (OkHttp)

import okhttp3.*;

OkHttpClient client = new OkHttpClient();

String json = "{\"accountId\":\"A12345\",\"offeringId\":\"O54321\",\"units\":100}";

RequestBody body = RequestBody.create(
    json, 
    MediaType.parse("application/json")
);

Request request = new Request.Builder()
    .url("https://api-sandboxdash.norcapsecurities.com/tapiv3/createTrade")
    .addHeader("Content-Type", "application/json")
    .addHeader("Authorization", "Bearer NC12345:sk_live_abc123xyz789")
    .post(body)
    .build();

Response response = client.newCall(request).execute();

Ruby (Net::HTTP)

require 'net/http'
require 'json'

uri = URI('https://api-sandboxdash.norcapsecurities.com/tapiv3/createTrade')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request['Authorization'] = 'Bearer NC12345:sk_live_abc123xyz789'

request.body = {
  accountId: 'A12345',
  offeringId: 'O54321',
  units: 100
}.to_json

response = http.request(request)

Backwards Compatibility

Both Methods Supported

Both authentication methods are supported:

  1. Authorization Header (Recommended, REQUIRED for GET endpoints)
  2. Body Parameters (POST/PUT only, not available for GET)

Method Availability by HTTP Verb

HTTP MethodHeader AuthBody AuthNotes
GET✅ Required❌ N/ANo request body in GET requests
POST✅ Supported✅ SupportedHeader auth recommended
PUT✅ Supported✅ SupportedHeader auth recommended
DELETE✅ Supported✅ SupportedHeader auth recommended

Priority Order

If credentials are provided in both headers and body (POST/PUT only):

  • Headers take precedence
  • Body credentials are ignored

Example with Both

# Authorization header will be used, body credentials ignored
curl -X POST https://api-sandboxdash.norcapsecurities.com/tapiv3/getAccount \
  -H "Authorization: Bearer NC12345:sk_live_abc123xyz789" \
  -d '{
    "developerAPIKey": "old_key_ignored",
    "clientID": "old_id_ignored",
    "accountId": "A12345"
  }'

Error Handling

Missing Headers

If authentication headers are missing and no body credentials are provided:

{
  "statusCode": 103,
  "statusDesc": "Invalid developer API Key"
}

Invalid Credentials

If the provided credentials (header or body) are invalid:

{
  "statusCode": 103,
  "statusDesc": "Invalid developer API Key"
}

Unauthorized Access

If credentials are valid but lack permission for the requested operation:

{
  "statusCode": 110,
  "statusDesc": "You do not have the required permissions"
}

Best Practices

1. Environment Variables

Store credentials in environment variables, not in code:

// Good
const apiKey = process.env.TAPI_API_KEY;
const clientId = process.env.TAPI_CLIENT_ID;

// Bad
const apiKey = 'sk_live_abc123xyz789'; // Never hardcode!

2. Configuration Management

Create a centralized configuration for API calls:

// config.js
module.exports = {
  baseURL: 'https://api-sandboxdash.norcapsecurities.com/tapiv3',
  headers: {
    'Authorization': `Bearer ${process.env.TAPI_CLIENT_ID}:${process.env.TAPI_API_KEY}`
  }
};

// usage.js
const config = require('./config');
const axios = require('axios');

const client = axios.create({
  baseURL: config.baseURL,
  headers: config.headers
});

// Now all requests automatically include auth headers
const response = await client.post('/createTrade', {
  accountId: 'A12345',
  offeringId: 'O54321',
  units: 100
});

3. Error Handling

Always handle authentication errors gracefully:

try {
  const response = await makeApiCall();
  // Process successful response
} catch (error) {
  if (error.response?.status === 401) {
    console.error('Authentication failed. Check your API credentials.');
  } else if (error.response?.status === 403) {
    console.error('Permission denied. Your API key may lack required scopes.');
  } else {
    console.error('API call failed:', error.message);
  }
}

4. Logging and Debugging

When logging requests, exclude sensitive headers:

// Create a sanitized request log
function logRequest(config) {
  const sanitized = {
    ...config,
    headers: {
      ...config.headers,
      'Authorization': 'Bearer ***REDACTED***'
    }
  };
  console.log('API Request:', sanitized);
}

Testing Your Implementation

1. Test Environment

Start with the sandbox environment:

  • Sandbox URL: https://api-sandboxdash.norcapsecurities.com/tapiv3
  • Use your sandbox credentials

2. Verify Headers Are Sent

Use a tool like curl with -v flag to see headers:

curl -v -X POST https://api-sandboxdash.norcapsecurities.com/tapiv3/ping \
  -H "Authorization: Bearer your_sandbox_id:your_sandbox_key"

3. Gradual Migration

  1. Update one endpoint to use headers
  2. Test thoroughly
  3. Update remaining endpoints
  4. Remove body credentials once all endpoints are updated

Frequently Asked Questions

Q: Is Authorization header authentication available in all environments?

A: Authorization header support varies by environment. Check with your account manager or test in your sandbox environment to confirm availability.

Q: Will my existing integrations break?

A: No. Body-based authentication will continue to work for POST/PUT/DELETE requests. However, GET endpoints require header authentication since they don't have request bodies.

Q: Do I need to update my GET endpoint calls?

A: Yes. All GET endpoints require the Authorization header. You cannot pass credentials as URL parameters for security reasons.

Q: Can I use different authentication methods for different endpoints?

A: Yes. You can use headers for some calls and body parameters for others. Each request is authenticated independently.

Q: Is the header name case-sensitive?

A: No. HTTP headers are case-insensitive. Authorization, authorization, and AUTHORIZATION all work.

Q: What if I accidentally send credentials in both headers and body?

A: Headers take precedence. Body credentials will be ignored if headers are present.

Q: Do webhook endpoints require these headers?

A: No. Webhook endpoints (callbacks from external services like DocuSign) have their own authentication mechanisms.

Support

For questions or issues with header authentication: