Skip to main content
Create Reputation Grant
Transfers reputation between two users. This is a debited transfer: the amount leaves the sender’s bucket and lands in the recipient’s bucket for the same space. Nothing is created — see Mint Reputation Grant for that. Requires authentication. A user token sends from the token’s own user. A service or master key may name any sender via actingUserId, which is how an app performs a mediated transfer — enforcing its own economic rules before letting the transfer through. Mediated transfers skip the project-level user-grant switch and ignore block relationships; they are otherwise identical to a user grant, including the balance check. Requires the reputation bundle (both ReputationBuckets and ReputationGrants must be present in the project’s schema).

Body Parameters

string
required
UUID of the user receiving the reputation. Must differ from the sender.
number
required
Whole number from 1 to 2147483647 (the signed 32-bit maximum, which is also the width of a reputation balance). A transfer can never be zero, negative, or fractional, and it can never exceed what the sender holds in the source bucket.
string | null
UUID of the space whose bucket pays. Omitted or null means the project-general bucket. The reputation always lands in the recipient’s bucket for the same space — reputation never crosses between the general bucket and a space bucket.The space is validated before anything moves: an ID that names no space is rejected with 404 reputation-grant/space-not-found, and naming a space on a project without the spaces bundle is rejected with 403 database/tables-not-available.
string | null
Free-text note. Trimmed, up to 2000 characters.
object
Arbitrary key-value data. Up to 1 MB. Omit the key when unused — null is not accepted.
string
What the grant is for: "entity", "comment", or "chat-message". Must be supplied together with targetId. The target is an annotation — it never determines which bucket is used, and it does not have to be authored by the recipient.
string
UUID of the rewarded record. Must be supplied together with targetType, and must exist at the time of granting.
string
Service/master key only. The sender — the user reputation is debited from. Spelled actingUserId rather than userId because this body already names a target user (recipientId). A user token may only name itself.

Response

Returns 201 with the created ReputationGrant, written with sourceType: "user". Both balances move: the sender’s bucket and profile total drop by amount, the recipient’s rise by the same. The recipient is notified (a reputation-grant app notification), and a chat-message-targeted grant is broadcast to the conversation as message:grant.

Gating and blocks

  • Project setting. The switch is settings.reputationGrants.allowUserInitiated, flipped from Settings → SDK in the dashboard. Only an explicit false closes the endpoint to user tokens — an absent key means grants are allowed — and the stored value survives unrelated settings updates, so it changes only when that key is explicitly sent. When the switch is off a user token is rejected with 403 reputation-grant/user-grants-disabled; service and master keys still work, so peer transfers remain available when routed through your backend.
  • Blocks. If either party has blocked the other, a user grant is rejected in both directions — with the same non-disclosing answer as a missing user. Service and master keys ignore block relationships.
  • Suspension. A suspended user cannot send a grant, including on the mediated path — a service key naming a suspended actingUserId is rejected too. A master key bypasses the check. A suspended user can always receive a grant.

Error Responses

Field-level failures are prefixed with the field path, so error reads "<path>: <message>""amount: Invalid input: expected int, received number" for a fractional amount, "recipientId: Invalid UUID format" for a malformed ID. The one whole-body rule has no path and so no prefix: supplying targetType without targetId (or the reverse) returns "targetType and targetId must be supplied together".
A service or master key called the endpoint without naming an actingUserId.
A user token named an actingUserId other than its own.
reason and endDate are null when the suspension carries neither.
The reputation bundle is missing — the route names both of its tables, so a project without it is told about both — or the target’s bundle is missing (e.g. a chat-message target without chat), or a spaceId was supplied on a project without spaces. missingTables names exactly what is absent.
The spaceId names no space in this project. Checked before any balance is touched, so nothing moves.
One answer for both parties, deliberately non-disclosing — and the same answer returned when a block edge exists in either direction.
The target record does not exist — or, for a chat-message target, the sender is not an active member of that conversation. The two cases are byte-identical so a caller holding a message ID cannot probe whether it exists. Mediated transfers are membership-checked on the named sender exactly as user tokens are.
Nothing moves. Also the answer when the spaceId names a real space the sender holds no funded bucket in.
Retryable. Two simultaneous transfers from the same bucket can never both succeed against the same balance.
Rate limit: 50 requests per 5 minutes per IP. Exceeding it returns 429 with a plain-text message and no code. See also: useCreateReputationGrant · node-sdk · js-sdk