Create a subscription checkout link
const url = 'https://secure.ethicsportal.eu/organizations/example/subscriptions/checkout.json';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"subscription":{"interval":"year"}}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://secure.ethicsportal.eu/organizations/example/subscriptions/checkout.json \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "subscription": { "interval": "year" } }'Return a Stripe Checkout link for the monthly or yearly plan. A person opens it and pays; Stripe handles strong customer authentication, tax and VAT ID collection. Access starts when Stripe confirms the payment, whether or not the payer is signed in to EthicsPortal. Send an Idempotency-Key so a retry returns the same link. A personal token also needs its user to be a current administrator.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Obfuscated organisation ID returned by identity.
Header Parameters
Section titled “Header Parameters”Recommended on every POST. Retrying with the same key and the same request within 24 hours returns the first response (with Idempotent-Replayed: true) instead of acting twice. Only successful responses and validation errors are stored; any other outcome releases the key. Reusing a key with a different request returns 409 idempotency_key_reused; a retry while the first request is still running returns 409 idempotency_key_in_progress. Keys are scoped to the token.
Request Bodyrequired
Section titled “Request Bodyrequired”object
object
Example
{ "subscription": { "interval": "year" }}Responses
Section titled “Responses”Checkout link created.
object
Stripe-hosted page. Give it to the person who pays or manages billing; it works for whoever holds it until it expires.
When the link stops working. Null for billing portal links, which expire shortly after creation; create one just before use.
Example
{ "url": "https://checkout.stripe.com/c/pay/cs_live_example", "expires_at": "2026-11-10T10:00:00Z"}Invalid body
object
object
Where to tell EthicsPortal what went wrong: POST product feedback here with the same token.
Example
{ "error": { "code": "invalid_request", "feedback_url": "https://secure.ethicsportal.eu/me/feedback.json" }}Missing, unknown, expired or revoked token
object
object
Where to tell EthicsPortal what went wrong: POST product feedback here with the same token.
Example
{ "error": { "code": "invalid_token", "feedback_url": "https://secure.ethicsportal.eu/me/feedback.json" }}The token lacks the required scope (WWW-Authenticate names it), the user’s role does not allow the action, or an agreement must be accepted in the web application
object
object
Where to tell EthicsPortal what went wrong: POST product feedback here with the same token.
Example
{ "error": { "code": "insufficient_scope", "feedback_url": "https://secure.ethicsportal.eu/me/feedback.json" }}Organisation missing or inaccessible, API access suspended, or billing not configured
object
object
Where to tell EthicsPortal what went wrong: POST product feedback here with the same token.
Example
{ "error": { "code": "not_found", "feedback_url": "https://secure.ethicsportal.eu/me/feedback.json" }}The organisation already has a subscription (use the billing portal link), or an Idempotency-Key conflict (This Idempotency-Key was already used with a different request, or its first request is still running)
object
object
Where to tell EthicsPortal what went wrong: POST product feedback here with the same token.
Example
{ "error": { "code": "already_subscribed", "feedback_url": "https://secure.ethicsportal.eu/me/feedback.json" }}Unknown interval
object
object
Where to tell EthicsPortal what went wrong: POST product feedback here with the same token.
Example
{ "error": { "code": "validation_failed", "fields": [ "interval" ], "feedback_url": "https://secure.ethicsportal.eu/me/feedback.json" }}Rate limited; retry after the Retry-After interval
object
object
Where to tell EthicsPortal what went wrong: POST product feedback here with the same token.
Example
{ "error": { "code": "rate_limited", "feedback_url": "https://secure.ethicsportal.eu/me/feedback.json" }}