Implant planning specifics
Service-specific details for integrating Relu's implant planning & tooth-supported guide service.
Implant planning is Relu Automate's most configurable service. This guide covers what differs from the generic order flow, parameter choices, implant-library filters, the beta service, exports, and billing.
Resources
- API URL:
https://api.automate.relu.ai/ - Endpoint:
POST /orders— the generic order route, the same one every other service uses.
Create implant-planning orders through POST /orders with a service_id, just like any other service. Pass the implant-planning service_id (below) plus the implant-specific input_data and parameter_values documented in this guide. The older dedicated routes (POST /orders/implant-planning and POST /orders/implant-planning-beta) still work but are slated for deprecation — use POST /orders for new integrations. The request body is identical either way.
Which service to use
There are two implant-planning services. Pass the service_id of the one you want:
| Service | service_id |
|---|---|
| Production — Implant Planning & Tooth Supported Guide | 587a7291-66ad-446d-b7fd-4d2c842f3f63 |
| Beta — [BETA] Implant Planning & Tooth Supported Guide | f47c8e0c-f1e5-49a4-8e70-42b1ab82cda0 |
Beta is not for production or medical use
The production service (587a7291-…) is the latest production-ready,
certified version — use it for production and any clinical / medical use. The
beta service (f47c8e0c-…) always carries the latest improvements ahead
of certification, but must not be used for medical purposes or in
production; reach for it only to preview and evaluate upcoming changes.
Integration options
Option A: full API order creation
Create the order entirely via the API. You pass every input file, parameter, and implant-library filter. You expose parameter choices in your own UI.
- Pro: maximum control over the UI.
- Con: you re-implement the parameter UI and keep it in sync with Relu's changes.
Option B: draft order + Relu's finalization UI (recommended)
Create a draft order with whatever you already have (typically input files) and let the user complete configuration in Relu's iframe.
- Pro: smooth UX, no UI to maintain, still handle files on your side.
- Con: less control over the parameter UI.
See Draft order flow for the walkthrough.
Input data
"input_data": {
"volume": {
"external_download_url": "https://.../scan.dcm",
"extension": ".dcm"
},
"upper_jaw": {
"external_download_url": "https://.../upper.stl",
"extension": ".stl"
},
"lower_jaw": {
"external_download_url": "https://.../lower.stl",
"extension": ".stl"
}
}volume(required), the CBCT scan..dcm(single DICOM) or.zip(folder of slices).upper_jaw/lower_jaw(optional, but required to generate a surgical guide), intra-oral scans..stl, 3Shape.dcm,.ply, or.obj.
Output data
"output_data": { "implant_planning": {} }The output bundle includes segmentations, a surgical report, a patient passport, and (once unlocked) surgical guides and design kits.
Set include_stl_mesh_bundle: true to also receive all unlocked meshes as a single STL zip — see STL mesh bundle.
Parameter reference
Implant library filters
Relu plans around several library components — the implant, the surgical kit, the sleeves, the abutment, and the wax-up. Each has its own filter list that narrows what the AI considers:
"parameter_values": {
"implant_filters": [
"folder = 'ETK'",
"productLine = 'iBone E'"
],
"surgical_kit_filters": [
"folder = 'ETK'",
"name = 'iBone Surgical Kit'"
],
"sleeve_filters": [
"folder = 'ETK'",
"productLine = 'ETK Full Guided Surgery'",
"pilot = false"
],
"abutment_filters": [
"folder = 'ETK'",
"productLine = 'iBone Abutment'"
],
"waxup_filters": [
"folder = 'generic'"
]
}implant_filters,surgical_kit_filters,sleeve_filters— narrow the implant, surgical kit, and sleeve catalogs respectively. Forsleeve_filtersspecifically, you can omit it and setprocedure_typeinstead — Relu then derives a manufacturer-matched, kit-recommended sleeve automatically (see Sleeve selection from the procedure type).abutment_filters— narrows the abutment product line. Leave it empty (or omit it) for "Any": the engine then picks an abutment per tooth from the catalog'spreferredTeeth. Set it only when you want to constrain the AI to a specific abutment line.waxup_filters— narrows the wax-up library (defaults tofolder = 'generic').
Each filter is a list of field = 'value' clauses combined together; omit a filter to use its default. The field names (folder, productLine, name, pilot, …) and their allowed values come from the live library — see below.
Per-implant filters
By default a filter list applies to every requested implant. To plan different teeth from different libraries, pass a per-tooth object keyed by FDI tooth number instead of a flat list. This works on any of implant_filters, sleeve_filters, surgical_kit_filters, abutment_filters, and waxup_filters:
"parameter_values": {
"teeth_with_implant": { "tooth14": "always", "tooth24": "always" },
"implant_filters": {
"tooth14": ["folder = 'BIOHORIZONS'", "productLine = 'Tapered Internal'"],
"tooth24": ["folder = 'ETK'", "productLine = 'iBone E'"]
},
"sleeve_filters": ["folder = 'generic'"],
"abutment_filters": {
"tooth24": ["folder = 'ETK'", "productLine = 'iBone Abutment'"]
}
}- List = global — the same filter for every implant (the default, unchanged).
- Object = per-tooth — each key is an FDI tooth (
"tooth14", same notation asteeth_with_implant) mapping to that tooth's filter clauses. - The form is chosen independently per filter: you can keep
sleeve_filtersglobal while makingimplant_filtersper-tooth (a mix), as above. - A requested tooth not listed in a per-tooth object falls back to that filter's engine default — a field is either global or per-tooth, never both, so list only the teeth you want to override.
- Tooth keys are validated; use the same FDI notation as the
teeth_*fields.
Use the live library
Call GET /implant-library/lists to get the current list of supported
manufacturers, product lines, surgical kits, sleeves, and abutments. Relu adds
libraries regularly, don't hardcode; re-fetch.
Implant locations
Tooth numbers use FDI notation only
All teeth_* fields use FDI / ISO 3950 two-digit numbers (11–48 for
permanent teeth, 51–85 for deciduous). The API treats every value as FDI
and does not detect Universal numbering — and the two systems share number
ranges that map to different teeth (e.g. FDI 14 is an upper-right premolar,
Universal 14 is an upper-left second molar). If your system uses Universal,
it's your responsibility to convert to FDI before calling the API.
"parameter_values": {
"teeth_to_extract": ["tooth11", "tooth21"],
"teeth_with_implant": {
"tooth11": "always",
"tooth21": "always",
"tooth12": "never"
},
"teeth_with_waxup": {
"tooth11": "always"
}
}Per tooth:
"predict"(default), the AI places an implant only if there's space. We recommend against this default, it can surprise users with unrequested implants."never", never place an implant here."always", always place an implant here. If a tooth is present, it's extracted.
teeth_to_extract explicitly schedules extractions. teeth_with_waxup works the same way for wax-ups.
Subcrestal placement depth
"parameter_values": {
"subcrestal_length_override": 1.5
}subcrestal_length_override sets how deep the implant platform sits below the bone crest, in mm. It is an advanced parameter. Leave it out unless the manufacturer's protocol or the clinician asks for a specific depth.
- Omitted or
null(default), each implant keeps the subcrestal depth defined for it in the implant library. 0, the platform sits at the bone crest.- A value above
0, the platform sits that many mm below the crest.
The value applies to every implant in the order. It has no per-tooth form, unlike the library filters. Negative values are invalid.
0 is not the same as leaving it out
0 is a real depth: it moves every implant to the crest, even when the
library defines a deeper placement for that implant. To keep the library
depth, omit the key or send null. Don't send 0 as an "unset" default.
Per-tooth temporary crowns
"parameter_values": {
"teeth_with_implant": { "tooth14": "always" },
"teeth_with_temp_crown": ["tooth14"]
}For each FDI tooth ID in teeth_with_temp_crown, the engine produces a tempCrown mesh output. Each listed tooth costs 3 credits at creation, refunded automatically if the order fails.
teeth_with_temp_crown is opt-in, the default (empty list / omitted) produces no temp crown outputs and no per-tooth charges. The list is independent of teeth_with_implant, listing a tooth here does not also schedule an implant.
Behavior change
Earlier versions of the API generated a temporary crown mesh for every
implanted tooth automatically, at no extra charge. Temp crowns are now opt-in
and each listed tooth adds a 3-credit upfront charge. Existing integrations
that relied on the implicit behavior should pass teeth_with_temp_crown with
the teeth they want crowns for.
Procedure type
"parameter_values": {
"procedure_type": "Pilot guide"
}Surgical procedure style. Controls whether a guide is generated, which sleeve system applies, and the upfront cost:
"Free-handed", no guide, no sleeves. No surcharge on top of the base order price."Pilot guide", pilot-only guide. +15 credits at creation; the surgical guide export is unlocked automatically (no separate unlock fee)."Fully guided", fully-guided guide. +15 credits at creation; the surgical guide export is unlocked automatically."2Ingis guide", 2Ingis-specific sleeve plan, no printable guide mesh. No surcharge; the surgical guide export is unlocked automatically.
Omit procedure_type to keep the legacy behavior, the guide is generated whenever an IOS scan is present, no procedure surcharge is added at creation, and the surgical guide export is unlocked separately via PUT /orders/{order_id}/purchase_addon (or pre-charged via unlocked_addons on the create call). Existing integrations that don't pass this field keep working unchanged.
Prefer setting it explicitly
Setting procedure_type on new integrations makes the total order cost
predictable at creation, and "Free-handed" is the only way to express "skip
the guide" at order time (the legacy path always generates a guide when an IOS
scan is present). Stick with omitting it only if your existing flow already
handles guide unlocks post-completion.
Sleeve selection from the procedure type
You no longer have to hand-build sleeve_filters. When you set procedure_type
and leave sleeve_filters unset (or at its default), Relu derives the sleeve
filter for you — scoped to the implant's own manufacturer and preferring the
surgical kit's recommended sleeve product line:
procedure_type | Derived sleeve |
|---|---|
"Free-handed" | the manufacturer's pilot sleeve |
"Pilot guide" | the manufacturer's pilot sleeve |
"Fully guided" | the manufacturer's guided sleeve (falls back to a pilot sleeve if a guided one can't be placed on the guide) |
"2Ingis guide" | the 2Ingis sleeve |
This is the recommended default for new integrations: set procedure_type,
omit sleeve_filters, and let Relu pick a sleeve that matches the implant system
and surgical kit. Sleeves from other manufacturers and universal (cross-system)
sleeve lines are intentionally excluded from this default — select one explicitly
if you need it.
Overriding is always available (non-breaking)
Passing an explicit sleeve_filters (e.g. ["folder = 'ETK'", "productLine = 'ETK Full Guided Surgery'"]) always wins and is sent to the planner
unchanged, on every procedure_type. The derivation only fills the unset case
— existing integrations that already build sleeve_filters behave exactly as
before.
Guide settings
"parameter_values": {
"guide_thickness": 2.3,
"printer_offset": 0.15,
"sleeve_printer_offset": 0.1,
"text_to_print": "engrave_order_name",
"guide_bar": "None",
"engrave_method": "engraved",
"window_positioning": "Next to implants",
"glue_holes": "disabled"
}guide_thickness, guide thickness in mm.printer_offset, offset between the guide and the jaw.sleeve_printer_offset, offset between sleeves and the guide.text_to_print, text to engrave."engrave_order_name"uses the order name;""disables engraving.guide_bar,None,Print, orPalatal.engrave_method,"engraved"(default) or"embossed".window_positioning,"Next to implants"(default) or"One in front, two in back".glue_holes,"disabled"or"enabled".
Finding your defaults
The easiest way to find your lab's right defaults is to create a few orders
through the Relu UI, then inspect the order-creation network call in your
browser dev tools to see the parameter_values the UI sent.
Advanced guide settings
"parameter_values": {
"window_distance_to_implants": 2,
"sleeve_gingiva_penetration_limit_mm": 0.5,
"min_support_teeth_per_side": 3,
"guide_tooth_coverage_mm": 5.0,
"allow_guided_sleeve_downgrading": true
}These parameters tune how the guide is built. The example shows the defaults, which suit most integrations. Send a key only when you want to change it.
| Parameter | Type | Default | Allowed values |
|---|---|---|---|
window_distance_to_implants | integer | 2 | 1 to 3 |
sleeve_gingiva_penetration_limit_mm | number | 0.5 | 0 to 1.5 |
min_support_teeth_per_side | integer | 3 | 1 to 8 |
guide_tooth_coverage_mm | number | 5.0 | 0.5 to 12 |
allow_guided_sleeve_downgrading | boolean | true |
window_distance_to_implants, the minimum number of interproximal gaps between a guide window and the nearest implant.1puts the window next to the implant.sleeve_gingiva_penetration_limit_mm, the deepest a sleeve may sink into the gingiva, in mm. Sleeve positions that go deeper are discarded.0allows no gingiva contact at all.min_support_teeth_per_side, the number of sound teeth the guide needs on each side of the implants before it is long enough to seat. A higher value extends the guide over damaged teeth. A lower value gives a shorter guide.guide_tooth_coverage_mm, how much of each tooth the guide outline covers, in mm, measured up from the gingival margin. A higher value makes the guide grip more of the tooth. A tooth shorter than the value is covered in full.allow_guided_sleeve_downgrading, whether a tooth may fall back to a pilot sleeve when its guided sleeve doesn't seat within the gingiva limit or doesn't clear the neighbouring tooth. This is the fallback described in Sleeve selection from the procedure type. Set it tofalseto keep the guided sleeve where possible.
Mesh output format
"parameter_values": {
"mesh_extension": "STL"
}Controls the file extension used for all mesh outputs of the order, including the surgical guide mesh, the waxed-up model, undercuts, teeth segmentations, and nerves. Pick what your downstream tooling expects:
"STL"(default), broadly supported by CAD/CAM and slicer software."PLY", Stanford polygon format."OBJ", plain-text mesh, easy to inspect.
This is an advanced parameter, the default "STL" is sufficient for most integrations. Switch to "PLY" or "OBJ" only if your post-processing pipeline needs it. The choice also flows through to the extension field on each mesh entry returned by GET /implant-orders/{order_id}/output-files.
STL mesh bundle
"parameter_values": {
"include_stl_mesh_bundle": true
}Off by default. When true, the order produces one extra zip containing every unlocked mesh deliverable as an STL with human-readable filenames (implant_11.stl, waxup_11.stl, mandible.stl, upper_guide.stl, …) — exactly the meshes you'd otherwise fetch individually, so locked exports stay out. A convenience for integrations that prefer a single download over per-mesh fetches; the per-file outputs and the viewer are unaffected.
It comes back alongside the other deliverables as type: "ZippedData", name: "all-meshes-stl-zip", with a signed download_url — see Downloading outputs.
Generated once, at first processing
The bundle is built a single time, when the order's first job completes. It is not regenerated if the case is recomputed or edited and re-saved in the viewer. Fetch it after the initial job; if you need meshes after edits, fetch them individually instead.
Fetching processing status
Polling
POST https://api.automate.relu.ai/orders/job-statuses
Content-Type: application/json
{ "order_ids": ["<order_id>"] }Check statuses[order_id].main_job.job_status for "Submitted", "Done",
"Failed", or "Cancelled". main_job is null until processing starts.
Missing and inaccessible orders appear in errors. Send no more than 100 order
IDs per request, and don't poll more often than every 10–30 minutes in
production.
Webhook
Pass callback_url when creating the order. Event types:
order.job_status, processing completed.order.status, approval status changed ("Approved","Rejected", or"Unapproved").order.outputs_edited, user edited and saved in the viewer.order.unlock, an export was unlocked (creates a billing event).
Each callback body contains event_type, order_id, and order_name.
Use both
Webhooks lower load on both sides. But poll at low frequency (e.g., every 30 minutes) as a safety net in case a webhook is missed.
Progress percentage
Use POST /orders/progress only for UIs that need progress bars. Use POST /orders/job-statuses to check for completion.
Approval & exports
Users must approve the treatment in the viewer before exports can be unlocked. Approval is toggleable; each change fires order.status.
Integrations can set the same status without the viewer:
PUT /orders/{order_id}/status?status=ApprovedThe request has no JSON body. Use Rejected to reject the result and
Unapproved to reset the decision. The API key needs update:orders scope, and
the API user needs order:approve permission on the completed order.
Available exports
- Surgical report & patient passport, included free with the planning.
- Segmentations, the anatomical meshes.
- Surgical guide (+ IOS model with a base for fit testing).
- Guide design kit, design the guide in external software.
- Crown design kit, design crowns in external software.
- Surgical navigation export, for XNav and similar systems.
Each export has an unlock cost. Once unlocked, it's free to re-download.
Billing
The cost is billed to the owner of the order, not whoever unlocks it. Whether to let end users unlock exports themselves, or do it from your backend, is your choice.
Branding the report PDFs with your logo
The surgical report and patient passport PDFs embed your organization's logo at the top, when one is set. The logo used is the one belonging to the organization that owns the order (the org of the API user who created it), not the end user who downloads the PDF — so it only needs to be set once, per integrating organization.
Two ways to set it:
-
From the Relu dashboard, an organization admin can open Settings → Organization → General and upload an image from the Logo card.
-
From the API, an org admin (or system admin) uses a two-step presigned-upload flow:
POST https://api.automate.relu.ai/organizations/{organization_id}/logo/upload-url POST https://api.automate.relu.ai/organizations/{organization_id}/logoStep 1 with
{ "extension": ".png", "size_bytes": 12345 }returns a presignedupload_urland ans3_file_id.PUTthe raw image bytes toupload_urlwith the matchingContent-Typeheader, then commit with step 2 ({ "s3_file_id": "...", "file_name": "logo.png" }).DELETE /organizations/{organization_id}/logoremoves the current logo.
Accepted formats: .png, .jpg / .jpeg, .svg, .webp. Max size: 5 MB.
Set the logo before placing orders
The logo is embedded into the surgical report and patient passport when the PDFs are first generated; once generated, the embedded logo doesn't change. Upload your logo before placing your first order, and re-upload ahead of time if you rebrand.
Unlocking from the backend
PUT https://api.automate.relu.ai/orders/{order_id}/purchase_addonUnlocks a specific export bundle, lets you control spend without exposing unlock buttons to end users.
Downloading outputs
GET https://api.automate.relu.ai/implant-orders/{order_id}/output-filesReturns the deliverable artifacts for the order, each with a time-limited
download_url. The response is filtered: only deliverables that are either
included by default OR whose export bundle is unlocked
are returned. Internal / intermediate engine outputs (per-tooth info JSON
files, contour XYZ files, viewer-only mesh variants, ...) are not included.
[
{
"id": "...",
"name": "surgical_report",
"type": "surgical_report",
"download_url": "https://.../abc.pdf",
"options": {}
},
{
"id": "...",
"name": "fused_tooth75",
"type": "meshes",
"download_url": "https://.../def.stl",
"options": { "extension": ".stl", "structures": ["fused_tooth75"] }
}
]Always returned (no unlock required)
type | What it is |
|---|---|
surgical_report, patient_passport, drilling_protocol | PDFs generated post-approval. Embed your org logo if set before order creation. |
meshes (bones + per-tooth) | Segmentation meshes shown in the implant viewer step: mandible, maxillary / skull, plus per-tooth (tooth<FDI> from the CBCT, or fused_tooth<FDI> if an IOS was registered). The structure is in options.structures[0]. |
WaxupMesh | Crown waxup STLs for every tooth flagged with a waxup. |
panoramic_arch | Panoramic arch curve used to render the panoramic view from the CBCT. |
registration_matrix_lower, registration_matrix_upper | 4×4 rigid transform aligning the IOS to the CBCT (JSON). Only present when an IOS was uploaded. |
Returned only when the matching export bundle is unlocked
| Addon | type | What it is |
|---|---|---|
EXPORT_GUIDES | guideMesh, upper_guide_model, lower_guide_model | Printable surgical guide STL(s). |
EXPORT_TEMP_CROWN_<FDI> (per tooth) | tempCrown | Temporary crown STL for the specified tooth. Identify the tooth via the name (TempCrownMesh_tooth<FDI>). |
EXPORT_MANDIBULAR_NERVE, EXPORT_SINUSES, EXPORT_AIRWAY | meshes | Extra anatomy meshes (nerves, sinuses, airway). Identify via options.structures[0]. |
EXPORT_UPPER_CLOSED_CROWNS, EXPORT_LOWER_CLOSED_CROWNS | meshes | Closed-crown variants from the IOS. |
EXPORT_REGISTERED_FACIAL_SCAN | meshes | Facial scan registered into CBCT space. |
Common fields
type— see the tables above for the meaningful values for implant orders.name— human-readable identifier. Per-tooth artifacts include the FDI tooth number (e.g.WaxupMesh_tooth11,TempCrownMesh_tooth13); per-jaw artifacts include the jaw (e.g.GuideMesh_lowerjaw,GuideModel_upperjaw).options.extension— for mesh outputs, reflects the format you picked viamesh_extension(.stlby default, or.ply/.obj).options.structure— the tooth FDI (tooth15) or jaw (lowerjaw/upperjaw) the row belongs to. Mirror of the suffix onname, also available onmeshesrows asoptions.structures(a list).download_url— expires after a while; re-fetch the order for fresh URLs.
Stable response shape
Integrations that already rely on surgical_report, patient_passport,
guideMesh and meshes rows continue to work — those type values and their
options shape are preserved. Intermediate engine outputs that used to leak
into the response (per-tooth WaxupInfo, transformation, marginLine,
guideOutline, ...) are now filtered out.
Consumables info
GET https://api.automate.relu.ai/implant-orders/{order_id}/planning-infoReturns which implants, abutments, and components were used, use this to create ordering records for the physical parts.
Billing
Implant orders cost 15 credits at creation, plus the surcharges driven by parameter_values: +15 credits when procedure_type is "Pilot guide" or "Fully guided", and +3 credits per tooth listed in teeth_with_temp_crown. Per-tooth temp-crown charges are refunded if the order fails. Other exports cost more on unlock. Volume discounts kick in at configured thresholds. Usage is billed monthly.
For refunds when an order produced no clinical value, see Submit feedback & request refunds.
Full example
A complete POST /orders body. Swap service_id for the beta service ID to run the beta version.
{
"service_id": "587a7291-66ad-446d-b7fd-4d2c842f3f63",
"order_name": "Patient #1234",
"input_data": {
"volume": {
"external_download_url": "https://.../scan.dcm",
"extension": ".dcm"
},
"lower_jaw": {
"external_download_url": "https://.../lower.stl",
"extension": ".stl"
},
"upper_jaw": {
"external_download_url": "https://.../upper.stl",
"extension": ".stl"
}
},
"output_data": { "implant_planning": {} },
"parameter_values": {
"guide_thickness": 2.3,
"printer_offset": 0.15,
"sleeve_printer_offset": 0.1,
"text_to_print": "",
"guide_bar": "None",
"glue_holes": "disabled",
"teeth_to_extract": ["tooth11", "tooth21"],
"teeth_with_implant": { "tooth11": "always", "tooth21": "always" },
"teeth_with_waxup": { "tooth11": "always", "tooth21": "always" },
"implant_filters": ["folder = 'ETK'", "productLine = 'iBone E'"],
"surgical_kit_filters": ["folder = 'ETK'", "name = 'iBone Surgical Kit'"],
"sleeve_filters": [
"folder = 'ETK'",
"productLine = 'ETK Full Guided Surgery'"
]
},
"callback_url": "https://your-app.com/relu-webhook"
}Related
- Draft order flow, recommended for end-user products
- Embed the iframe viewer, in-app review and approval
- Sharing & permissions, inviting doctors and technicians
- Feedback & refunds, the refund lifecycle
Submit feedback & request refunds
Record quality feedback on an order, and optionally request a credit refund if the result wasn't clinically useful.
Crown & Bridge specifics
Service-specific details for integrating Relu's Crown & Bridge Models service — per-tooth margin lines, pre-designed crowns, and die engraving options.