curl --request POST \
--url https://api.mage.space/v1/references \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Red coat",
"handle": "red-coat",
"kind": "outfit",
"image": "https://example.com/red-coat.jpg"
}
'import requests
url = "https://api.mage.space/v1/references"
payload = {
"name": "Red coat",
"handle": "red-coat",
"kind": "outfit",
"image": "https://example.com/red-coat.jpg"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'Red coat',
handle: 'red-coat',
kind: 'outfit',
image: 'https://example.com/red-coat.jpg'
})
};
fetch('https://api.mage.space/v1/references', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"id": "a81f0c5d-2e6b-4f93-b7c4-0d9e5a3c2f18",
"handle": "red-coat",
"name": "Red coat",
"kind": "outfit",
"description": null,
"image_url": "https://cdn3.mage.space/references/user/image/4c2d.jpg",
"audio_url": null,
"created_at": "2026-09-18T10:05:00.000Z"
}{
"error": {
"code": "invalid_request",
"message": "`name` is required."
}
}{
"error": {
"code": "unauthorized",
"message": "The API key is invalid or has been revoked."
}
}{
"error": {
"code": "forbidden",
"message": "This account cannot create characters or references."
}
}{
"error": {
"code": "handle_taken",
"message": "The handle `@ana` is taken. Choose another, or omit `handle` to derive one from the name.",
"handle": "ana"
}
}{
"error": {
"code": "internal_error",
"message": "Something went wrong on our side. Retry, and contact support if it persists."
}
}Create reference
POST /v1/references saves a private image or audio reference and returns the handle a prompt mentions it by.
curl --request POST \
--url https://api.mage.space/v1/references \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Red coat",
"handle": "red-coat",
"kind": "outfit",
"image": "https://example.com/red-coat.jpg"
}
'import requests
url = "https://api.mage.space/v1/references"
payload = {
"name": "Red coat",
"handle": "red-coat",
"kind": "outfit",
"image": "https://example.com/red-coat.jpg"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'Red coat',
handle: 'red-coat',
kind: 'outfit',
image: 'https://example.com/red-coat.jpg'
})
};
fetch('https://api.mage.space/v1/references', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"id": "a81f0c5d-2e6b-4f93-b7c4-0d9e5a3c2f18",
"handle": "red-coat",
"name": "Red coat",
"kind": "outfit",
"description": null,
"image_url": "https://cdn3.mage.space/references/user/image/4c2d.jpg",
"audio_url": null,
"created_at": "2026-09-18T10:05:00.000Z"
}{
"error": {
"code": "invalid_request",
"message": "`name` is required."
}
}{
"error": {
"code": "unauthorized",
"message": "The API key is invalid or has been revoked."
}
}{
"error": {
"code": "forbidden",
"message": "This account cannot create characters or references."
}
}{
"error": {
"code": "handle_taken",
"message": "The handle `@ana` is taken. Choose another, or omit `handle` to derive one from the name.",
"handle": "ana"
}
}{
"error": {
"code": "internal_error",
"message": "Something went wrong on our side. Retry, and contact support if it persists."
}
}name, a kind, and the media for that kind. An object, location, pose, or outfit takes an image (an https URL, an upload URL, or a data URL of a JPEG or PNG), stored with the reference for as long as it exists. An audio reference takes an audio clip (MP3 or WAV) instead, which goes through the same processing as a clip uploaded in the app: trimmed to 15 seconds and normalized.
The handle follows the same rules as a character’s: 1 to 15 lowercase letters, digits, underscores, or dashes, starting with a letter, unique among live characters and references, and fixed once created. Leave it out to have one derived from the name. A handle already in use is a 409 handle_taken.
References created through the API are private.Authorizations
An API key from Settings → API, sent as Authorization: Bearer mage_sk_…. Keys are for server-side code only.
Body
The display name.
1 - 50What the reference is. The four image kinds take image; audio takes audio.
object, location, pose, outfit, audio The @handle prompts mention it by: 1 to 15 lowercase letters, digits, underscores, or dashes, starting with a letter. Derived from the name when omitted. Cannot be changed later.
The image, for the four image kinds: an https URL, an upload URL, or a data URL of a JPEG or PNG. Stored permanently with the reference.
The clip, for kind: "audio": an https URL, an upload URL, or a data URL of an MP3 or WAV. Trimmed to 15 seconds and normalized, like a clip uploaded in the app.
Optional notes, for your own reference.
500Response
The reference.
The reference id, as DELETE /v1/references/{reference_id} takes it.
Mention the reference in a prompt as @handle.
The display name.
What the reference is.
object, location, pose, outfit, audio Your notes, or null.
The image, for the four image kinds; null for an audio reference.
The processed clip, for kind: "audio"; null otherwise.
When it was created.

