Skip to main content

Authentication

Every request carries an API key. Some keys additionally require a request signature. Both are configured per key in the MineTech portal under Developers → API Keys.

API keys​

Authorization: Bearer mt_live_a1b2c3d4e5f6g7h8i9j0k1l2
PrefixEnvironmentBase URL
mt_live_…Productionhttps://api.minetech.rw
mt_test_…Sandboxhttps://sandbox.api.minetech.rw

The key carries its own tenant, so there is no tenant header to send. The SDK infers the base URL from the prefix — you cannot accidentally point a live key at sandbox.

What a key is, and is not​

A key cannot call the authentication endpoints (/v1/auth/*) or manage other keys. Those are reserved for interactive sessions, so a leaked key cannot escalate itself into a user login or mint further credentials.

A key can be scoped, expired, IP-restricted and rate-limited. Prefer several narrow keys over one broad one: it makes rotation cheap and blast radius small.

Storage​

Keys are stored as a bcrypt hash. MineTech cannot show you a key again after creation and cannot recover one for you — rotation is the only path. Treat the signing secret the same way.

Request signing​

Live keys require signing by default. It proves the request body was not altered in transit and bounds replay to a five-minute window.

Send two extra headers:

x-mt-timestamp: 1735689600
x-mt-signature: t=1735689600,v1=<hex HMAC-SHA256>

The signed string is:

{timestamp}.{METHOD}.{path-with-query}.{sha256hex(body)}

Concretely, for GET /v1/operations/lots?page=2 with an empty body at 1735689600:

1735689600.GET./v1/operations/lots?page=2.e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

HMAC that string with your signing secret, hex-encode it, and send it as v1. The t= value must equal the x-mt-timestamp header.

The SDK does all of this when you pass signingSecret:

const client = new MineTech({
apiKey: process.env.MINETECH_API_KEY!,
signingSecret: process.env.MINETECH_SIGNING_SECRET!,
});

Full worked examples in several languages: Request signing.

Your clock matters

Signatures are valid for 300 seconds either side of server time. A timestamp_stale error is a clock problem, not a secret problem — check NTP on the calling host before regenerating anything.

IP allowlists​

Optionally restrict a key to specific addresses or CIDR blocks under Developers → IP Allowlist, per environment.

An empty allowlist means requests are accepted from any address. It is not a partially-configured state — if you add no entries, no IP restriction applies. Add at least one entry for the restriction to take effect.

Both IPv4 and IPv6 are supported, including IPv4-mapped IPv6 (::ffff:10.0.0.1 matches 10.0.0.0/8), so enabling IPv6 at your edge will not silently break an allowlist.

Errors​

StatusCodeMeaningFix
401api_key_missingNo Authorization headerSend Bearer <key>
401api_key_invalidUnrecognised keyUsually a truncated copy
401api_key_revokedKey was revokedIssue a new key
401api_key_expiredPast its expiryRotate the key
401signature_missingKey requires signingSend both signing headers
401timestamp_staleOutside the 300s windowFix the host clock
401signature_mismatchDigest did not matchCheck the canonical string
403insufficient_scopeKey lacks the scopeGrant it in the portal
403ip_not_allowedSource address not allowlistedAdd the address
429rate_limit_exceededPer-key limit exceededHonour Retry-After

Each signing failure is reported distinctly on purpose — "your clock is skewed" and "your secret is wrong" need different fixes, and collapsing both into a generic 401 makes integration debugging guesswork.

Rotation​

Rotating issues the replacement before revoking the old key, so there is never a window with no working credential. The old key stops working as soon as rotation completes, so deploy the new one first.

Rotation mints a new signing secret as well. Update both.