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.