Repository navigation
Releases: getabyssale/abyssale-python-sdk
Release list
v1.7.0
Models regenerated against API version v2026-10-21, which also brings v2026-10-20. Minor: three methods were added and an enum gained members. Nothing was removed or narrowed, so there is no upgrade step beyond installing it.
Added
- rename_design(design_id, {"name": ...}), move_design(design_id, {"project_id": ...}) and delete_design(design_id) on both the sync and async clients: PUT /designs/{designId}/name, PUT
/designs/{designId}/project and DELETE /designs/{designId}. All three return a DesignNameResult (id, name), exported from abyssale.models. Moving a design resets its approval status; deleting has no restore. A design list_designs does not list raises AbyssaleAPIError with id "template_not_found"; a destination that is not a project of the workspace, "project_not_found". - Border on image layers: stroke_width (0 to 60) and stroke_color on an image element override. The frame is drawn outside the image box and follows its mask. Bodies are plain dicts, so nothing to change.
- Justified text: a text element's alignment accepts justify, justify-left, justify-center and justify-right, alone or after a vertical half ("middle justify-center"). Text layers only.
Full changelog: https://github.com/getabyssale/abyssale-python-sdk/blob/main/CHANGELOG.md
API changelog: https://developers.abyssale.com/rest-api/changelog
v1.6.0
Models regenerated against API version v2026-10-19, which also brings v2026-10-12. Minor: the text-to-image model enum gained a member. Nothing was removed or narrowed, so there is no upgrade step beyond installing it. abyssale.__api_version__ now reads v2026-10-19.
Added
textEffecttweens reveal a text per letter, word or line (v2026-10-19): a design import's keyframeattrmay carrytextEffectSplit(letter, the default,wordorline) andtextEffectTiming
(in, the default,outorinOut, the layout of an effect that plays out). The keyframeattrmodel is an open map, so no model changed; only its documentation did.ideogram-4.5joins thetext_to_image_properties.modelenum (v2026-10-12).
Changed
inpaint_imageshas a maximum per model (v2026-10-12), from 3 to 16 images; the table is in the field's description and the model caps the list at 16. A request with more than the selected model accepts is rejected by the API with a validation error.
Full changelog: https://github.com/getabyssale/abyssale-python-sdk/blob/main/CHANGELOG.md
API changelog: https://developers.abyssale.com/rest-api/changelog
v1.5.0
Generated from API version v2026-10-07, which also brings v2026-10-02.
Minor: the three listings gained keyword arguments. Every existing call keeps working, including list_designs(type="static"): type now also takes a list.
Added
- Search, filters, sort and paging on
list_designs(v2026-10-07):query(words in any order, in the design or the project name),name,project,orientation,size,format,updated_since,created_since,sort,order,pageandper_page.type,sizeandformattake a string or a list, sent comma-separated as the API expects; the dates take an ISO 8601 string, adateor adatetime. - Filters and paging on
list_fonts(name,category,weight,style) andlist_projects(name). Both took no argument before. - Models:
Font.category(Google fonts), andleonardo-remove-bgamong the background-removal models (v2026-10-02).
The total across pages (the X-Total-Count header) is not exposed: the listings still return a plain list. When paging, a page shorter than per_page is the last one.
See List Designs for what each filter does, and the API changelog.
v1.4.0
Generated from API version v2026-10-01, which also brings v2026-09-30.
Minor: the models gained the upscale settings and new model names. Nothing was removed or narrowed, so there is no upgrade step beyond installing it.
Added
- Upscale on the image element (
v2026-09-30):upscaleandupscale_propertieson the asynchronous image element, modelled byUpscaleProperties(model:seedvr-upscale,topaz-precision,crystal-upscalerorbria-increase-resolution;upscale_factor:1to4). Asynchronous generation only: the API refuses it on synchronous generation. Request bodies stay plain dicts, so this is documentation for what you send, not a new class to import. - Three text-to-image and inpainting models (
v2026-09-30):gpt-image-2.5-sunburst,gpt-image-2.5-flareandseedream-5-pro. design_in_open_productamong the documented error ids.
Changed
- Colour fields document radial gradients (
v2026-10-01). Every field that takes a linear gradient also takesradial-gradient(cx% cy% r%,<stops>): a centre and a radius as percentages of the layer's box, then the same 2 to 8 stops. A colour is astreither way, so only the field descriptions changed. See the API changelog.
v1.3.1
Generated from API version v2026-09-25.
Patch: no model gained or lost a field and no type changed (a colour is a str either way). The regeneration only rewrote the descriptions of the colour fields to the one colour grammar v2026-09-25 publishes.
Changed
- Colour fields document what you may send. Hex is
#RRGGBB,#RRGGBBAA,#RGBor#RGBA; CMYK iscmyk(C,M,Y,K)orcmyka(C,M,Y,K,A), each component an integer 0–100, optionally followed by%. A gradient stop is#RRGGBB,#RGBorcmyk(C,M,Y,K)at an offset of0%to100%. A stop has no alpha: its transparency is the stop opacity (0to1).
Worth knowing: an API change, not an SDK one
v2026-09-25 refuses with 400 invalid_payload colours it used to draw wrong or fail on:
- a CMYK component or alpha above
100 - a gradient stop offset above
100% - a stop opacity above
1 - a 4-digit hex gradient stop
Request bodies are plain dicts passed through untouched, so this reaches you whatever SDK version you run, as an AbyssaleAPIError whose id is invalid_payload. See the API changelog.
v1.3.0
Generated from API version v2026-09-24.
Minor, not patch: the models gained fields. No method changed, no signature moved, and nothing that worked against 1.2.0 needs touching. A generation body is a plain dict either way.
Added
-
A
buttonelement acceptsicon_url,icon_encodedandicon_color.icon_urlis a public HTTP(s) URL of an image to place beside the label;icon_encodedis its base64 / data-URI twin, for an icon
held in memory (icon_urlwins if both are sent).icon_colorrecolours the icon and only applies to an SVG. Sending an icon for a button designed without one adds it on the left, at the label's font size.
The icon's size, gap and side belong to the design and are not overridable per generation.client.generate_image( template_id, elements={"button_0": {"icon_url": "https://example.com/star.svg", "icon_color": "#FF0000"}}, )
-
A
buttonelement acceptstext_shadow_color,text_shadow_blur,text_shadow_offset_xandtext_shadow_offset_y. A button has two shadows: the existingshadow_*properties are the shadow of the
button box, and these four are the shadow of its label. -
An
imageelement accepts the five auto-focus properties at the top level:auto_focus_model,focus_objects,focus_framing,focus_targetandfocus_zoom, the flat form ofauto_focus_properties.*.
The nested form wins when both are sent. Thefacemodel is deprecated; usepeoplewithfocus_framing. -
An
imageelement acceptsexpandandexpand_properties: AI image expansion (outpainting), which extends the image past its borders to fill the target area instead of cropping or letterboxing it.
Changed
- Colour fields document a linear gradient of 2 to 8 stops instead of exactly two, and say where print accepts one: only a shape or button
background_color. The models are unchanged; a colour is astr
either way.
v1.2.0
Generated from API version v2026-09-02.
Minor, not patch: one new client method. Nothing existing changed shape, so there is no upgrade step beyond installing it.
Added
get_credits()on both clients — the newGET /credits, returning the workspace's remaining credits for the current billing period asgeneration_creditsandai_credits, each aCreditBlockofavailable,limit,consumedandextra. The read
costs no credits.
Two things to know before branching on the numbers. available and limit are null on an unlimited plan — and since the generated models type nullable fields as plain int (as they do for Design.project_id), the tolerant parse is what keeps the
None readable; test for None before comparing, because available > 0 raises on an unlimited workspace. And available counts the recurring allowance only, so what a request can still spend is available + extra.
CreditsBalanceandCreditBlockare exported fromabyssale.models.
v1.1.0
Generated from API version v2026-08-21.
Minor, not patch: three new client methods and a new public module. Nothing existing changed shape,
so there is no upgrade step beyond installing it.
Added
abyssale.webhooks — a new public module (the third, after abyssale and
abyssale.models) with verify_webhook_signature and signature_timestamp. It imports only the
standard library: no client, no httpx. That is the point of it being separate — a process that
only receives deliveries should not have to hold a credential that can spend credits, and a test
asserts the import graph so the property cannot rot.
Pass the raw body: the signature covers the bytes as sent, so a parsed-and-re-serialised dict
reorders keys and never matches. It returns False and never raises on a missing, malformed, forged
or stale header — anyone who finds a webhook URL can POST to it, and an exception in a handler is a
500 plus, on most frameworks, a retried delivery. It checks every v1 in the header, because a
rotation puts two there for 24 hours.
get_signing_secret(), rotate_signing_secret(force=False), revoke_signing_secret() on both
clients — the three /signing-secret endpoints. Deliveries are unsigned until
get_signing_secret() is called once; fetching the secret is what turns signing on. A refused
second rotate raises AbyssaleAPIError with id="previous_secret_still_active" and is not
retried — it is a state conflict, not a transient failure. force is omitted from the query
string entirely when false, so an ordinary rotate stays a bare POST.
SigningSecret response model, generated from the spec.
Fixed
FocusZoomis a string enum, not a boolean. It generated asFalse_ = False— a boolean
member in atype: stringenum — because the spec wroteenum: [off, low, medium, max]
unquoted and PyYAML reads bareoffas a YAML 1.1 boolean.openapi-typescriptreads YAML 1.2,
where it is a string, which is why only this SDK carried the defect. Nowoff = 'off', matching
the deployed bundle.
v1.0.0
Generated from API version v2026-08-20.
First release. Covers every operation in that spec — 18 of them — plus two polling helpers over
its status endpoints. Response models are generated from its schemas. Requires Python 3.10+.
Added
AbyssaleandAsyncAbyssale, overhttpx. Both are context managers and both accept a
caller-suppliedhttpxclient.- All 18 endpoints — auth; design list/read/format read; sync and async generation; multipage
PDF; generation-request status; file read; fonts; projects list/create; export; dynamic image
URL; workspace templates, categories, duplication and duplication status. wait_for_generation_request/wait_for_duplication_request— exponential backoff with
jitter, a 30-minute default deadline, and a budget of three consecutive transient failures that
resets on any successful poll. Partial success resolves: a finalized request carrying both banners
and per-format errors is a result, not an exception. Only a request that finalized with no banners
at all and at least one error raises.- Retries that follow the spec's error contract — 5xx on idempotent methods only (every POST
bills credits, and a 504 does not mean the render did not happen); the full ladder for a429
carryingRetry-After; exactly one one-second probe for a bare429, because
rate_limit_exceededconflates spent credits with the gateway's per-second ceiling;
feature_not_in_plannever retried, whatever headers the response carries. max_retry_wait($ABYSSALE_MAX_RETRY_WAIT_MS, default 30s) — the longest single
Retry-Afterthe SDK will sleep through on your behalf. The rate limiter can name a cool-off of
~1700s once a quota is spent, andmax_retriesmultiplies it, so honouring it blindly would turn
one call into 83 minutes of silence. Past the bound the call fails immediately with
AbyssaleRateLimitError,retry_aftercarrying the server's figure so the decision is yours.
Passmath.infto wait however long the server asks.- An exception hierarchy under
AbyssaleError, built from the API's single error envelope — the
machine-readableidis always on the exception, anderrorsholds the per-field problems when
the failure was a payload problem. - Pydantic response models generated from the spec, with the Alpha design-import surface
stripped byscripts/fetch_spec.py. - Seven runnable examples in
examples/, each exercising a documented operation end to end.
Notes
- Request bodies are plain dicts. The
elementsschema is ananyOfof ten deliberately
overlapping branches with no discriminator, and the API accepts unknown element names by design,
so bodies are passed through untouched rather than modelled. - Parsing never fails a successful response. Unknown fields are kept, and a field the spec
calls required but the response omits does not raise — the spec is hand-maintained and the API is
the authority.