{% extends "base.html" %} {% block title %}{{ t('nav.api') }} — painfree{% endblock %} {% block body %}
{{ t('api.lede') }}
{# This page is about the machine-facing side of the service, and that side is English by decision: an endpoint path, a scope name, an error `code` and an audit `action` are contract values a consumer matches on, so translating one would break every client. What is translated here is the prose around them. What is not is said so on the page rather than left to look like a hole in the catalogue. #}{{ t('api.english_notice') }}
| {{ name }} | {{ blurb }} {{ base_url }}{{ path }} |
{{ t('api.schema_note') }}
{{ t('api.basic_credential') }} {{ t('api.basic_why') }}
{{ t('api.basic_get_one') }}
curl -u "$PAINFREE_ACCOUNT:$PAINFREE_PASSWORD" \
-H "Idempotency-Key: $(uuidgen)" \
-X POST {{ base_url }}/v1/connections/<connection>/payments \
-d @payment.json
{{ t('api.basic_tls') }}
{{ t('api.basic_throttle') }}
{% else %}{{ t('api.no_tokens') }} {{ t('api.no_tokens_why') }}
{{ t('api.get_a_token') }}
curl -H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-X POST {{ base_url }}/v1/connections/<connection>/payments \
-d @payment.json
{% endif %}
| {{ t('api.mode') }} | {{ auth_mode }}
{{ auth_mode_reason }} {% if auth_mode == 'development' %} {{ t('api.development_mode') }} {% endif %} {% if auth_mode == 'basic' %} {{ t('api.basic_mode') }} {% endif %} |
| {{ t('api.basic_scheme') }} | Basic realm="painfree" |
| {{ t('api.basic_hash') }} | {{ password_hashing }} |
| {{ t('api.basic_lockout') }} | {{ t('api.basic_lockout_value') }} |
| {{ t('api.issuer') }} | {{ provider.issuer or t('api.not_configured') }} |
| {{ t('api.audience') }} | {{ provider.audience or '—' }} |
| {{ t('api.client_id') }} | {{ provider.client_id or '—' }} |
| {{ t('api.roles_claim') }} | {{ provider.roles_claim }} |
| {{ t('api.scope_claim') }} | {{ provider.scope_claim }} |
{{ t('api.basic_sign_out') }}
{% else %}{{ t('api.roles_note') }}
{% endif %}| {{ t('access.subject') }} | {{ me.subject }} |
| {{ t('api.issuer') }} | {{ me.issuer }} |
| {{ t('api.authenticated_by') }} | {{ me.method }} |
| {{ t('api.role') }} | {{ me.role }}
{% if me.role == 'admin' %}
{{ t('api.role_admin') }} {% else %} {{ t('api.role_member') }} {% endif %} |
| {{ t('access.access') }} |
{% if me.role == 'admin' %}
{{ t('api.every_connection') }}
{% elif me.oversight and not me.grants %}
oversight {{ t('access.every_connection_readonly') }}
{% elif me.grants %}
{% if me.oversight %}oversight
{{ t('access.every_connection_readonly') }} {% endif %} {% for grant in me.grants %} {{ grant.connection_id }} {{ grant.level }}{{ '' if loop.last else ' · ' }} {% endfor %} {% else %} {{ t('api.no_grants') }} {% endif %} |
| {{ t('api.claimed_roles') }} | {{ me.roles | join(', ') or t('access.none') }}
{% if unmapped %}
{# A provider that starts sending a role name this service has no mapping
for grants nothing, silently. Saying so here is the difference between a
five-minute fix and an afternoon. #}
{{ t('api.unmapped') }} {% for name in unmapped %}{{ name }}{{ '' if loop.last else ', ' }}{% endfor %} {% endif %} |
| {{ t('api.expires') }} | {{ me.expires_at or '—' }} |
| {{ t('api.effective_scopes') }} |
{% if me.scopes %}
{% for name in me.scopes %}{{ name }}{{ '' if loop.last else ' · ' }}{% endfor %}
{% if me.role != 'admin' and not me.oversight %}
{{ t('api.scopes_per_connection') }} {% elif me.oversight %} {{ t('api.scopes_oversight') }} {% endif %} {% else %} {{ t('api.scopes_none') }} {% endif %} |
{{ t('api.auth_me') }} GET /auth/me{{ t('api.auth_me_tail') }}
{{ t('api.privileges_lede') }}
| {{ t('api.scope') }} | {{ t('api.what_it_allows') }} | {% for row in roles %}{{ t('api.role_column') }}: {{ row.role }} | {% endfor %} {% for row in grant_levels %}{{ t('api.level_column') }}: {{ row.level }} | {% endfor %}oversight | {{ t('api.you_column') }} |
|---|---|---|---|---|---|
| {{ scope.scope }} | {{ scope.summary }}
{% if scope.admin_only %}
{{ t('api.admin_only') }} {% endif %} |
{% for row in roles %}
{{ '✓' if scope.scope in row.scopes else '—' }} | {% endfor %} {% for row in grant_levels %}{{ '✓' if scope.scope in row.scopes else '—' }} | {% endfor %}{{ '✓' if scope.oversight else '—' }} | {{ '✓' if scope.held else '—' }} |
{{ t('api.oversight_carries') }} {% for name in oversight_scopes %}{{ name }}{{ '.' if loop.last else ' · ' }}{% endfor %} {{ t('api.oversight_derived') }}
{{ t('api.endpoints_lede') }}
| {{ t('api.method') }} | {{ t('api.path') }} | {{ t('api.what') }} | {{ t('api.needs') }} |
|---|---|---|---|
| {{ row.method }} | {{ row.path }} | {{ row.summary }} |
{% if row.role %}
{{ row.role }} {{ t('api.only') }}
{{ t('api.a_role_not_a_scope') }} {% elif row.scopes %} {% for name in row.scopes %}{{ name }}{{ '' if loop.last else ' + ' }}{% endfor %} {% if row.per_connection %} {{ t('api.on_this_connection') }} {% endif %} {% elif row.public %} {{ t('api.no_credential') }} {% else %} {{ t('api.any_authenticated') }} {% endif %} |
{{ t('api.any_credential_why') }}
{{ t('api.any_credential_none') }}
{% endif %}{{ t('api.public_paths') }}