DocsGetting started
Integrations
Everything you need to call the ShareShield v2 API from a script or pipeline. For every endpoint and schema, see the API reference in the app.
- Base URL
- https://app.shareshield.net/api/v2
- Auth
- x-api-key header
- Full reference
- API v2 reference
- Machine-readable
- OpenAPI 3.1 spec
API keys
Create a key in the app under Dashboard → Profile → API keys. A key:
- looks like
shs_followed by 64 hex characters, and is shown once. ShareShield stores only a hash; the dashboard shows its prefix (for exampleshs_ab12cd34…) so you can tell keys apart; - is bound to one organisation, the one that was active when you created it, and stops working if its owner leaves that organisation;
- is scoped: it can only do what its scopes allow, and never more than its owner's role allows;
- can expire (after 1–365 days) and can be revoked at any time by its owner or an organisation admin. Expired and revoked keys get
401.
Keys can't manage the account: users, invitations, roles, settings, policies, SSO, billing and API keys themselves are only available to a signed-in session, so a leaked key can't mint new keys or invite anyone. Organisation admins can list and revoke every key in the organisation.
Your first call
Send the key in the x-api-key header. GET /api/v2/me tells you who the key belongs to:
export SHARESHIELD_URL=https://app.shareshield.net
export SHARESHIELD_API_KEY=shs_…
curl -sS "$SHARESHIELD_URL/api/v2/me" -H "x-api-key: $SHARESHIELD_API_KEY"Requests and responses are JSON (send content-type: application/json; file uploads are multipart/form-data). Lists are newest first and paginated with a cursor. Every response carries X-API-Version: 2.
Scopes
A key's permission is the intersection of its scopes and its owner's role. A scope never grants more than the role allows: a viewer's key can't create secrets even with secrets:create. New keys default to every scope your role allows; give integrations only the ones they need.
| Scope | Allows | Needs role permission |
|---|---|---|
secrets:create | Create secrets and file secrets in the organization. | secrets:create |
secrets:read | Reveal (and so use a view of) a secret by its id. | secrets:read |
secrets:burn | Destroy secrets the key owner created. | secrets:create |
secrets:list | List metadata of the key owner's secrets (never their content). | secrets:read |
requests:create | Ask someone to send you a secret. | secrets:create |
requests:read | List the key owner's secret requests. | secrets:read |
audit:read | Read the organization's audit log. | audit:read |
Owners and admins can use every scope; members every scope except audit:read; viewers secrets:read, secrets:list and requests:read.
Using it from CI
Store the key as a CI secret, ideally one with only secrets:create and an expiry. This GitHub Actions step sends a password to a colleague as a one-time, recipients-only link:
- name: Send the staging database password to the on-call engineer
env:
SHARESHIELD_URL: https://app.shareshield.net
SHARESHIELD_API_KEY: ${{ secrets.SHARESHIELD_API_KEY }} # a key with only secrets:create
DB_PASSWORD: ${{ secrets.STAGING_DB_PASSWORD }}
run: |
jq -n --arg content "$DB_PASSWORD" \
'{content: $content, expiryHours: 4, maxViews: 1,
recipients: ["[email protected]"], recipientsOnly: true}' \
| curl -sS --fail-with-body -X POST "$SHARESHIELD_URL/api/v2/secrets" \
-H "x-api-key: $SHARESHIELD_API_KEY" \
-H "content-type: application/json" \
--data @- \
| jq '{expiresAt, recipients}'The response includes the share link, but the step prints only the expiry and the per-address delivery report. Treat a share link like the secret itself and keep it out of build logs. Sending to recipients needs an authenticated caller and respects your organisation's recipient domain allow-list.
Errors
Errors always have the same shape. Branch on code, which is stable, rather than on the message:
{
"error": "Missing scope secrets:create",
"code": "INSUFFICIENT_SCOPE",
"details": { … }
}| Status | Code | Meaning |
|---|---|---|
400 | VALIDATION_ERROR | The body or query failed validation (unknown fields included); details.issues lists each problem. |
401 | UNAUTHORIZED | Missing, invalid, expired or revoked key. |
402 | PAYMENT_REQUIRED | Over a plan ceiling: monthly quota, expiry, views, or files on a plan without them. Upgrading fixes it. |
403 | FORBIDDEN | The owner's role or the organisation's policy does not allow it. |
403 | INSUFFICIENT_SCOPE | The key lacks the scope the endpoint needs (details.requiredScope). |
404 | NOT_FOUND | No such secret or request. |
410 | GONE | Already viewed, burned or expired. |
415 | UNSUPPORTED_MEDIA_TYPE | The body is not application/json (or multipart/form-data for a file upload). |
429 | TOO_MANY_REQUESTS | Rate limited; back off and retry later. |
These are the common ones. The API reference lists every code, including those specific to files, recipients and requests, and the errors each endpoint can return.
Rate limits
Going over a limit returns 429 TOO_MANY_REQUESTS. Limits are counted in fixed windows shared by every app instance. The ones an integration is most likely to meet:
- Revealing, downloading, checking and burning secrets: 30 attempts per IP per minute, shared.
- Secret requests: 20 per user per hour and 100 per organisation per day.
- Recipient emails: 100 recipients per user per hour and 500 per organisation per day.
- Unknown links: an IP that tries 20 links that don't exist in an hour gets
429on every lookup until the hour ends.
Separately, plan quotas and ceilings answer 402 and organisation policy ceilings 403. Call GET /api/v2/options to read the limits that apply to your key before you hit them.
