Gravity API

Use the hosted Gravity models from your own tools. The API follows the OpenAI chat format, so most existing clients work by changing the base URL and key.

Overview

Base URL: https://iamgravity.eu/api/gravity/v1

All requests and responses are JSON, sent over HTTPS. Usage is charged to your Gravity token balance. Buy tokens before you start. Prompts and answers are not stored.

API keys

Create a key in your account under API keys (profile menu). A key looks like grav_ followed by random characters. It is shown once, so copy it right away. Only a hash is kept on our side. You can have up to 10 active keys and revoke any of them at any time; a revoked key stops working immediately.

Send the key in the Authorization header of every request:

Authorization: Bearer grav_xxxxxxxxxxxxxxxxxxxxxxxx

The Gravity desktop app signs in on its own and uses its session token in the same header; you do not need a key for the app.

Keep keys secret. Do not put them in browser code, public repositories or screenshots.

List models

GET /models

GET /api/gravity/v1/models
Authorization: Bearer grav_...

Response:

{
  "object": "list",
  "data": [
    {
      "id": "gravity-coder",
      "object": "model",
      "owned_by": "gravity",
      "name": "Gravity Coder",
      "description": "Tuned for writing and fixing code across several files.",
      "context_window": 32768,
      "max_output_tokens": 4096,
      "pricing": { "input_per_1k": 70, "output_per_1k": 105 }
    }
  ]
}

Use the id as the model value in chat requests. pricing is the number of Gravity tokens charged for every 1,000 tokens the model reads (input) or writes (output). The list depends on what is currently available.

Chat completions

POST /chat/completions

POST /api/gravity/v1/chat/completions
Authorization: Bearer grav_...
Content-Type: application/json

{
  "model": "gravity-coder",
  "messages": [
    { "role": "system", "content": "You are a careful C# reviewer." },
    { "role": "user", "content": "Explain what this method does." }
  ],
  "max_tokens": 1024,
  "temperature": 0.2,
  "stream": false
}

Response:

{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "model": "...",
  "choices": [
    { "index": 0, "message": { "role": "assistant", "content": "..." }, "finish_reason": "stop" }
  ],
  "usage": { "prompt_tokens": 42, "completion_tokens": 180, "total_tokens": 222 }
}
FieldNotes
modelRequired. An id from GET /models.
messagesRequired. Non-empty list of system, user, assistant and tool messages. Maximum request size 2 MB.
max_tokensOptional. Capped to the model limit and to what your balance can pay for.
temperature, top_p, stop, toolsOptional, passed to the model when it supports them.
streamOptional. true returns server-sent events.
n, user, stream_optionsIgnored.

Streaming

With "stream": true the response is text/event-stream. Each event is a line starting with data: that holds a JSON chunk, and the stream ends with data: [DONE].

data: {"choices":[{"index":0,"delta":{"content":"Hello"}}]}

data: {"choices":[{"index":0,"delta":{"content":" world"}}]}

data: [DONE]

If you close the connection early, you are charged for what was generated so far.

Balance

GET /api/gravity/balance (note: no /v1)

{ "balance": 482310, "buy_url": "https://iamgravity.eu/GravityAi" }

Billing

Cost of a request in Gravity tokens, rounded up, minimum 1:

cost = ceil( prompt_tokens / 1000 x input_per_1k + completion_tokens / 1000 x output_per_1k )

Your balance never goes below zero. Before a request runs we check the balance can cover the prompt, and the answer length is limited to what the balance can still pay for. When the model does not report usage while streaming, the tokens are estimated.

Errors and limits

Errors use this shape:

{ "error": { "message": "Not enough Gravity tokens. Buy more at https://iamgravity.eu/GravityAi", "type": "gravity_error", "code": "insufficient_tokens" } }
HTTPcodeMeaning
400invalid_requestBody is not valid JSON, messages is missing, or the model rejected the request.
401invalid_api_keyMissing, wrong or revoked key.
402insufficient_tokensBalance too low. Buy tokens.
404model_not_foundUnknown or unavailable model id.
413request_too_largeRequest larger than 2 MB.
429rate_limitedMore than 60 requests per minute per account, or the model is busy. Retry after a moment.
502 / 503provider_error, service_unavailableTemporary problem on our side. Retry with a short delay. Failed requests are not charged.

Examples

curl

curl https://iamgravity.eu/api/gravity/v1/chat/completions \
  -H "Authorization: Bearer $GRAVITY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"gravity-coder","messages":[{"role":"user","content":"Write a C# extension method to chunk a list."}]}'

C#

using var http = new HttpClient { BaseAddress = new Uri("https://iamgravity.eu/api/gravity/v1/") };
http.DefaultRequestHeaders.Authorization = new("Bearer", Environment.GetEnvironmentVariable("GRAVITY_API_KEY"));

var response = await http.PostAsJsonAsync("chat/completions", new
{
    model = "gravity-coder",
    messages = new[] { new { role = "user", content = "Explain dependency injection in two sentences." } }
});
response.EnsureSuccessStatusCode();
Console.WriteLine(await response.Content.ReadAsStringAsync());

Python (OpenAI SDK)

from openai import OpenAI

client = OpenAI(base_url="https://iamgravity.eu/api/gravity/v1", api_key="grav_...")
reply = client.chat.completions.create(
    model="gravity-coder",
    messages=[{"role": "user", "content": "Hello"}],
)
print(reply.choices[0].message.content)