Docs
Search docs

Invite email addresses to collaborate on a repository

POST/api/repos/{owner}/{repo}/invites

createRepoInvite

Required role: `repo:admin`. Takes 1 to 50 addresses and one repo role, and answers per address. Each new invite is single-use and its accept link is mailed to the address; the token is never returned to the inviter (ADR 0164): only a signed-in account holding the address verified can accept, and the grant it creates is bound to the address — it lapses when the account stops holding the address verified. Per-address outcomes: `invited`, `mail_failed` (created but not sent — resend it), `already_invited` (an open invite exists; resend rotates it), `already_has_access` (a grant bound to the address already holds the role or more), `invalid`, and `rate_limited` (the inviting account's mail budget is spent). Entries are trimmed and case-folded, never split; duplicates are dropped. 400 for an empty list, more than 50 entries, or a synthetic load-cohort repository.

Requires authentication using a bearer token or a session cookie — see tokens and scopes.

curl

curl -X POST 'https://neosource.dev/api/repos/OWNER/REPO/invites' \
  -H 'Authorization: Bearer $NEOSOURCE_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"emails":[],"role":"string"}'

fetch

fetch("https://neosource.dev/api/repos/OWNER/REPO/invites", {
  method: "POST",
  headers: {
    Authorization: "Bearer $NEOSOURCE_TOKEN",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"emails":[],"role":"string"}),
});

Path parameters

ownerrequired

Repository owner or organization slug.

string

reporequired

Repository name.

string

Request bodyrequired

application/json

CreateRepoInviteRequest

object

emailsrequired

array

Email addresses to invite, 1 to 50. Each entry is one address: it is trimmed and case-folded, and the server splits nothing. Duplicates after folding are dropped.

items

string

rolerequired

RepoRole

string

Repo-level role (read/write/maintain/admin). Ordered low → high so `if role >= RepoRole::Write` reads naturally.

"read""write""maintain""admin"

ttl_seconds

integer | nullint64

Optional override for time-to-live in seconds. Defaults to 7 days. Capped server-side at 30 days.

Responses

200One result per distinct address

application/json

InviteBatchResponse

object

One result per distinct address, in request order.

resultsrequired

array

items

InviteResult

object

What one address of an invite request came to.

emailrequired

string

The address as folded, or the trimmed entry as sent when it is `invalid`.

invite_id

string | null

Set when an invite was created (`invited`, `mail_failed`).

outcomerequired
InviteOutcome

Standard errors

Bodies documented once for the whole API — see standard errors.

  • 400Bad Request — one of: invalid_input
  • 401Authentication required
  • 403Forbidden — one of: forbidden
  • 404Not Found — one of: not_found
  • 409Conflict — one of: already_exists, conflict, non_fast_forward
  • 423Locked — one of: busy
  • 429Rate limited — retry after the `Retry-After` header
  • 500Internal server error
  • 503Service temporarily unavailable / at capacity — retry after the `Retry-After` header
  • 504Gateway timeout — the request exceeded the server's handling budget

Schemas

Referenced above. Listed here rather than expanded inline, so the same definition is not repeated at every level.

InviteOutcome

string

Per-address outcome of an invite batch, on the wire (ADR 0164).

"invited""mail_failed""already_invited""already_has_access""invalid""rate_limited"