Authentication
NotaryCam API uses JWT (JSON Web Token) authentication. Exchange your API credentials for a token, then include it in all subsequent requests.
Quick Overview
Step 1: Obtain a Token
Endpoint
POST /api/v4/authorize/
Request
- JavaScript/Node.js
- Python
- C#/.NET
- cURL
const axios = require('axios');
async function authenticate() {
const response = await axios.post(
'{BASE_URL}/api/v4/authorize/',
{
partnerId: 'your-partner-id',
apiKey: 'your-api-key',
apiSecret: 'your-api-secret'
},
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
return response.data.token;
}
// Usage
const token = await authenticate();
console.log('Token:', token);
import requests
def authenticate():
response = requests.post(
'{BASE_URL}/api/v4/authorize/',
data={
'partnerId': 'your-partner-id',
'apiKey': 'your-api-key',
'apiSecret': 'your-api-secret'
},
headers={'Content-Type': 'application/x-www-form-urlencoded'}
)
return response.json()['token']
# Usage
token = authenticate()
print(f'Token: {token}')
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
public class AuthResponse
{
[JsonProperty("success")]
public bool Success { get; set; }
[JsonProperty("token")]
public string Token { get; set; }
}
public async Task<string> Authenticate()
{
using var client = new HttpClient();
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("partnerId", "your-partner-id"),
new KeyValuePair<string, string>("apiKey", "your-api-key"),
new KeyValuePair<string, string>("apiSecret", "your-api-secret")
});
var response = await client.PostAsync(
"{BASE_URL}/api/v4/authorize/",
content
);
var json = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<AuthResponse>(json);
return result.Token;
}
// Usage
string token = await Authenticate();
Console.WriteLine($"Token: {token}");
curl -X POST {BASE_URL}/api/v4/authorize/ \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "partnerId=your-partner-id" \
-d "apiKey=your-api-key" \
-d "apiSecret=your-api-secret"
Response
{
"success": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXJ0bmVySWQiOiJ5b3VyLXBhcnRuZXItaWQiLCJpYXQiOjE3MDk1NjgwMDAsImV4cCI6MTcwOTY1NDQwMH0.abc123def456"
}
Step 2: Use the Token
Include the token in the Authorization header for all API requests:
Authorization: Bearer {your-token}
Example API Request
- JavaScript/Node.js
- Python
- C#/.NET
const axios = require('axios');
async function getTransaction(transactionId, token) {
const response = await axios.get(
`{BASE_URL}/api/v4/transactions/${transactionId}`,
{
headers: {
'Authorization': `Bearer ${token}`
}
}
);
return response.data;
}
// Usage
const transaction = await getTransaction('transaction-id-123', token);
import requests
def get_transaction(transaction_id, token):
response = requests.get(
f'{BASE_URL}/api/v4/transactions/{transaction_id}',
headers={'Authorization': f'Bearer {token}'}
)
return response.json()
# Usage
transaction = get_transaction('transaction-id-123', token)
using System.Net.Http;
using System.Net.Http.Headers;
public async Task<Transaction> GetTransaction(string transactionId, string token)
{
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token);
var response = await client.GetAsync(
$"{BASE_URL}/api/v4/transactions/{transactionId}"
);
var json = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Transaction>(json);
}
// Usage
var transaction = await GetTransaction("transaction-id-123", token);
Token Expiration
Expiration Time
- Lifetime: 24 hours from issuance
- Check expiration: Decode the JWT to see
expclaim
Handling Expiration
Implement token refresh logic:
- JavaScript/Node.js
- Python
class NotaryCamAPI {
constructor(baseUrl, credentials) {
this.baseUrl = baseUrl;
this.credentials = credentials;
this.token = null;
this.tokenExpiry = null;
}
async ensureAuthenticated() {
const now = Date.now();
// Refresh token if expired or not set
if (!this.token || !this.tokenExpiry || now >= this.tokenExpiry) {
await this.authenticate();
}
}
async authenticate() {
const response = await axios.post(
`${this.baseUrl}/api/v4/authorize/`,
this.credentials,
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
this.token = response.data.token;
// Set expiry to 23 hours from now (1 hour buffer)
this.tokenExpiry = Date.now() + (23 * 60 * 60 * 1000);
}
async makeRequest(method, endpoint, data = null) {
await this.ensureAuthenticated();
return axios({
method,
url: `${this.baseUrl}${endpoint}`,
data,
headers: {
'Authorization': `Bearer ${this.token}`,
'Content-Type': 'application/json'
}
});
}
}
// Usage
const api = new NotaryCamAPI('{BASE_URL}', {
partnerId: process.env.NOTARYCAM_PARTNER_ID,
apiKey: process.env.NOTARYCAM_API_KEY,
apiSecret: process.env.NOTARYCAM_API_SECRET
});
// Automatically handles token refresh
const transaction = await api.makeRequest('GET', '/api/v4/transactions/123');
import requests
from datetime import datetime, timedelta
class NotaryCamAPI:
def __init__(self, base_url, credentials):
self.base_url = base_url
self.credentials = credentials
self.token = None
self.token_expiry = None
def ensure_authenticated(self):
now = datetime.now()
# Refresh token if expired or not set
if not self.token or not self.token_expiry or now >= self.token_expiry:
self.authenticate()
def authenticate(self):
response = requests.post(
f'{self.base_url}/api/v4/authorize/',
data=self.credentials,
headers={'Content-Type': 'application/x-www-form-urlencoded'}
)
self.token = response.json()['token']
# Set expiry to 23 hours from now (1 hour buffer)
self.token_expiry = datetime.now() + timedelta(hours=23)
def make_request(self, method, endpoint, data=None):
self.ensure_authenticated()
return requests.request(
method,
f'{self.base_url}{endpoint}',
json=data,
headers={'Authorization': f'Bearer {self.token}'}
)
# Usage
api = NotaryCamAPI('{BASE_URL}', {
'partnerId': os.environ['NOTARYCAM_PARTNER_ID'],
'apiKey': os.environ['NOTARYCAM_API_KEY'],
'apiSecret': os.environ['NOTARYCAM_API_SECRET']
})
# Automatically handles token refresh
transaction = api.make_request('GET', '/api/v4/transactions/123')
Security Best Practices
1. Protect Your Credentials
Never Expose Credentials
Never commit API credentials to version control or expose them in client-side code.
** Good Practices:**
// Use environment variables
const credentials = {
partnerId: process.env.NOTARYCAM_PARTNER_ID,
apiKey: process.env.NOTARYCAM_API_KEY,
apiSecret: process.env.NOTARYCAM_API_SECRET
};
// Use a secrets manager
const credentials = await secretsManager.getCredentials('notarycam');
** Bad Practices:**
// Don't hardcode credentials
const credentials = {
partnerId: 'partner-abc123', // Never do this!
apiKey: 'key-xyz789',
apiSecret: 'secret-def456'
};
// Don't commit .env files
// Add .env to .gitignore
2. Secure Token Storage
Store tokens securely:
- Server-side: Memory or encrypted cache
- Never in: Cookies, localStorage, or client-side code
- HTTPS only: Always use HTTPS for API calls
3. Rotate Credentials Regularly
- Rotate API keys periodically
- Update credentials if compromised
- Use separate credentials for different environments
4. Monitor API Usage
- Log authentication attempts
- Monitor for unusual API activity
- Set up alerts for failed authentication
Error Handling
Common Authentication Errors
| Error Code | Meaning | Solution |
|---|---|---|
| 400 | Bad Request | Check request format and required fields |
| 401 | Unauthorized | Verify credentials are correct |
| 403 | Forbidden | Check API access permissions |
| 429 | Too Many Requests | Implement rate limiting and backoff |
Handling Authentication Errors
- JavaScript/Node.js
async function authenticateWithRetry(maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await axios.post(
'{BASE_URL}/api/v4/authorize/',
{
partnerId: process.env.NOTARYCAM_PARTNER_ID,
apiKey: process.env.NOTARYCAM_API_KEY,
apiSecret: process.env.NOTARYCAM_API_SECRET
},
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
return response.data.token;
} catch (error) {
if (error.response?.status === 401) {
throw new Error('Invalid credentials - check your API keys');
}
if (error.response?.status === 429) {
const delay = Math.pow(2, i) * 1000; // Exponential backoff
console.log(`Rate limited. Retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
if (i === maxRetries - 1) throw error;
}
}
}
Testing Authentication
Test Authentication
Always test authentication before going to production:
const api = new NotaryCamAPI('{BASE_URL}', {
partnerId: process.env.NOTARYCAM_PARTNER_ID,
apiKey: process.env.NOTARYCAM_API_KEY,
apiSecret: process.env.NOTARYCAM_API_SECRET
});
Verify Token
Decode the JWT to verify contents (for debugging):
// Decode JWT (base64)
function decodeJWT(token) {
const parts = token.split('.');
const payload = Buffer.from(parts[1], 'base64').toString();
return JSON.parse(payload);
}
const decoded = decodeJWT(token);
console.log('Token expires:', new Date(decoded.exp * 1000));
Next Steps
Now that you understand authentication:
- Test it → Try authenticating in sandbox
- Build wrapper → Create an API client class
- Continue → Quick Start Guide
- Learn more → Security Best Practices
Troubleshooting
"Invalid credentials" error?
- Double-check Partner ID, API Key, and API Secret
- Ensure using correct environment and base URL
- Verify credentials haven't expired
Token expires too quickly?
- Implement automatic token refresh
- Check system clock is synchronized
- Consider token caching strategy
Need help?
- Email: support@notarycam.com
- See: Common Errors