{"openapi":"3.1.0","info":{"title":"Morph Embedded","version":"1","description":"Morph's import engine in your product: start importer sessions for your customers, send files through the engine, and receive clean records. Make a server key in Settings → Morph Embedded."},"servers":[{"url":"https://morph-vereon.com/embedded/v1"}],"security":[{"serverKey":[]}],"tags":[{"name":"Importer sessions"},{"name":"Engine"},{"name":"Email and SFTP"},{"name":"Records"},{"name":"Import logs"},{"name":"Connect"},{"name":"Audit log"},{"name":"Schemas"},{"name":"Customers"},{"name":"Headless mapping"}],"paths":{"/sessions":{"post":{"tags":["Importer sessions"],"summary":"Start an importer session for one customer","description":"Call from your server each time a customer opens the importer, and hand the token to your page (MorphImporter.open's getSessionToken). The customer is added the first time Morph sees their id. A session lasts 15 minutes. language (en, fr, de, es or nl) sets the importer's and Connect's language for this session, over your setting in Settings; a language given on the page itself wins over both.","operationId":"postSessions","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tenant":{"type":"string","minLength":1,"maxLength":200},"tenant_name":{"type":"string","minLength":1,"maxLength":200},"user":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":200},"email":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"name":{"type":"string","maxLength":200}},"required":["id"]},"language":{"description":"The importer's and Connect's language for this session: en, fr, de, es or nl. Without it, your setting in Settings applies.","type":"string","enum":["en","fr","de","es","nl"]}},"required":["tenant","user"]},"example":{"tenant":"cust_123","tenant_name":"Brook Supplies","user":{"id":"user_42"},"language":"fr"}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string"},"expires_at":{"type":"string","format":"date-time"}},"required":["token","expires_at"]}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/jobs":{"post":{"tags":["Engine"],"summary":"Send one file through the engine","description":"Morph maps the file itself (the customer's saved mapping for this layout, then your standard, then its own matching), checks and converts every row, and delivers the records like an import. When a required field can't be matched with confidence the job stops as needs_mapping with questions; confirm once with POST /mappings and that layout maps itself from then on. Inline files up to 4 MB. By file.url, a CSV up to 2 GB, read as it arrives (never held whole), and a workbook up to 50 MB. A workbook is read from its first sheet with data, or from the sheet named in sheet: send a workbook with a sheet per data type once per sheet. A PDF or a scan (.pdf, .png, .jpg, .tif) is read with OCR into one record of your fields when you've switched on documents in Settings, or into a record per line of the invoice when the schema's documentLines is on (the document's own fields on every line).","operationId":"postJobs","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tenant":{"type":"string","minLength":1,"maxLength":200},"tenant_name":{"type":"string","minLength":1,"maxLength":200},"target_schema":{"type":"string","pattern":"^[A-Za-z][A-Za-z0-9_]{0,63}$"},"mapping_id":{"type":"string","minLength":1,"maxLength":100},"mapping":{"type":"object","propertyNames":{"type":"string","pattern":"^[A-Za-z_][A-Za-z0-9_.]{0,99}$"},"additionalProperties":{"type":"object","properties":{"column":{"type":"string","maxLength":300},"constant":{"type":"string","maxLength":500},"transforms":{"default":[],"maxItems":10,"type":"array","items":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"trim"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"uppercase"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"lowercase"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"parse_number"},"decimal":{"default":".","type":"string","enum":[".",","]}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"parse_date"},"format":{"type":"string","enum":["YYYY-MM-DD","DD/MM/YYYY","MM/DD/YYYY","DD-MM-YYYY","DD.MM.YYYY","D MMM YYYY","MMM D, YYYY","YYYY/MM/DD","DD/MM/YY","MM/DD/YY"]}},"required":["kind","format"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"parse_boolean"},"true":{"maxItems":20,"type":"array","items":{"type":"string","maxLength":50}},"false":{"maxItems":20,"type":"array","items":{"type":"string","maxLength":50}}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"map_values"},"map":{"type":"object","propertyNames":{"type":"string","maxLength":200},"additionalProperties":{"type":"string","maxLength":200}}},"required":["kind","map"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"default"},"value":{"type":"string","maxLength":500}},"required":["kind","value"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"part"},"separator":{"default":" ","type":"string","minLength":1,"maxLength":10},"index":{"type":"integer","minimum":-5,"maximum":20},"rest":{"default":false,"type":"boolean"}},"required":["kind","index"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"replace"},"find":{"type":"string","minLength":1,"maxLength":100},"with":{"default":"","type":"string","maxLength":100}},"required":["kind","find"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"remove_characters"},"characters":{"type":"string","minLength":1,"maxLength":30}},"required":["kind","characters"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"titlecase"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"keep"},"what":{"type":"string","enum":["digits","letters","letters_and_digits"]}},"required":["kind","what"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"add_text"},"text":{"type":"string","minLength":1,"maxLength":50},"at":{"type":"string","enum":["start","end"]}},"required":["kind","text","at"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"add_column"},"column":{"type":"string","minLength":1,"maxLength":300},"separator":{"default":" ","type":"string","maxLength":10}},"required":["kind","column"],"additionalProperties":false}]}}},"additionalProperties":false}},"sheet":{"type":"string","minLength":1,"maxLength":256},"file":{"anyOf":[{"type":"object","properties":{"content_base64":{"type":"string","minLength":1},"filename":{"type":"string","minLength":1,"maxLength":255}},"required":["content_base64","filename"],"additionalProperties":false},{"type":"object","properties":{"url":{"type":"string","format":"uri"},"filename":{"type":"string","minLength":1,"maxLength":255}},"required":["url"],"additionalProperties":false}]}},"required":["tenant","target_schema","file"]},"example":{"tenant":"cust_123","tenant_name":"Brook Supplies","target_schema":"Invoice","file":{"url":"https://files.example.com/invoices.csv"}}}}},"responses":{"202":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"job_id":{"type":"string"},"status":{"type":"string"}},"required":["job_id","status"]}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/jobs/{job_id}":{"get":{"tags":["Engine"],"summary":"A job's status, counts and questions","description":"status: queued, running, completed, failed or needs_mapping (then with columns, suggested_mapping and questions).","operationId":"getJobsByJobId","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/tenants/{external_id}/jobs":{"get":{"tags":["Engine"],"summary":"A customer's latest jobs","description":"Newest first, for about a week: the files you sent, and the files the customer sent to their email address or SFTP folder (via email or sftp). A job that stopped as needs_mapping has the file's columns and questions: confirm once with POST /mappings and that layout maps itself from then on. Morph doesn't keep the file, so the customer sends that one again.","operationId":"getTenantsByExternalIdJobs","parameters":[{"name":"external_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Up to 200 (default 50).","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/Job"}}},"required":["jobs"]}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/tenants/{external_id}/inboxes":{"get":{"tags":["Email and SFTP"],"summary":"A customer's email addresses","operationId":"getTenantsByExternalIdInboxes","parameters":[{"name":"external_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"inboxes":{"type":"array","items":{"$ref":"#/components/schemas/Inbox"}}},"required":["inboxes"]}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}},"post":{"tags":["Email and SFTP"],"summary":"Give a customer an email address for one schema","description":"Each file attached to an email sent to the address (CSV, TSV or Excel; a PDF or scan when documents are on), up to 20 an email, goes through the customer's saved mapping for its layout, then your standard and Morph's matching, and is delivered like an import, as a job (GET /tenants/{external_id}/jobs). A file Morph can't map with confidence stops as needs_mapping. Anyone holding the address can send files for the customer: switch it off with DELETE /inboxes/{inbox_id}. Neither the email nor its files are kept.","operationId":"postTenantsByExternalIdInboxes","parameters":[{"name":"external_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"schema":{"type":"string","pattern":"^[A-Za-z][A-Za-z0-9_]{0,63}$"}},"required":["schema"]},"example":{"schema":"Invoice"}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Inbox"}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"409":{"description":"inboxes_off: email addresses for customers aren't switched on in Morph yet.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/inboxes/{inbox_id}":{"delete":{"tags":["Email and SFTP"],"summary":"Switch an email address off","description":"Mail sent to it from now on is dropped.","operationId":"deleteInboxesByInboxId","parameters":[{"name":"inbox_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Done"},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/tenants/{external_id}/sftp":{"get":{"tags":["Email and SFTP"],"summary":"A customer's SFTP folder","operationId":"getTenantsByExternalIdSftp","parameters":[{"name":"external_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SftpFolder"}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}},"put":{"tags":["Email and SFTP"],"summary":"Give a customer an SFTP folder, or replace its key","description":"The customer signs in with their SSH key (keys only, never a password) and finds a folder for each of your schemas: a file put in /Invoice is imported as Invoice, through their saved mapping like a file sent by email, as a job. Each file leaves the folder once read. A new key replaces the old one. Answers 201 when the folder is new.","operationId":"putTenantsByExternalIdSftp","parameters":[{"name":"external_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"public_key":{"type":"string","maxLength":8192,"pattern":"^(ssh-ed25519|ssh-rsa|ecdsa-sha2-nistp256|ecdsa-sha2-nistp384|ecdsa-sha2-nistp521) [A-Za-z0-9+/]+={0,3}( [^\\r\\n]*)?$"}},"required":["public_key"]},"example":{"public_key":"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGqK0b5Yx3bXcW3yH8sQ1lqfLr6ZfNnS6rC2u0Q9d1hX brook@laptop"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SftpFolder"}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"409":{"description":"sftp_off: Morph's SFTP server isn't on; no_schemas: add a schema first.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}},"delete":{"tags":["Email and SFTP"],"summary":"Remove a customer's SFTP folder","description":"Nobody can sign in as the customer again, and anything still in the folder is deleted.","operationId":"deleteTenantsByExternalIdSftp","parameters":[{"name":"external_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Done"},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/batches/{batch_id}":{"get":{"tags":["Records"],"summary":"Collect an import's records (once)","description":"For imports not sent to a webhook. Each record is returned once and then deleted; a large import comes in pages, so call again while remaining_parts is above zero. Undelivered imports are deleted after 24 hours.","operationId":"getBatchesByBatchId","parameters":[{"name":"batch_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"batch_id":{"type":"string"},"status":{"type":"string"},"tenant":{"anyOf":[{"type":"string"},{"type":"null"}]},"counts":{"type":"object","properties":{"received":{"type":"integer"},"valid":{"type":"integer"},"invalid":{"type":"integer"},"skipped":{"type":"integer"},"delivered":{"type":"integer"}},"required":["received","valid","invalid","skipped","delivered"]},"records":{"type":"array","items":{"type":"object","additionalProperties":true}},"remaining_parts":{"type":"integer"}},"required":["batch_id","status","tenant","counts","records","remaining_parts"]}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/tenants/{external_id}/logs":{"get":{"tags":["Import logs"],"summary":"A customer's import logs","description":"Each import and each Connect sync run of the last 30 days: what came in, the rows with problems (row, field, why), what your app refused and where the records went. Never a value. Show them in your product so customers can see what happened.","operationId":"getTenantsByExternalIdLogs","parameters":[{"name":"external_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Up to 200 (default 50).","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/ImportLog"}}},"required":["logs"]}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/logs/{id}":{"get":{"tags":["Import logs"],"summary":"One import log","operationId":"getLogsById","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportLog"}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/tenants/{external_id}/connections":{"get":{"tags":["Connect"],"summary":"A customer's connected systems and their syncs","description":"The systems a customer connected in the Connect window, each with the syncs that bring its records into your schemas. A system built with your own connector has provider \"custom\" and its connectorId. Never a credential.","operationId":"getTenantsByExternalIdConnections","parameters":[{"name":"external_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"connections":{"type":"array","items":{"type":"object","additionalProperties":true}}},"required":["connections"]}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/tenants/{external_id}/writes":{"post":{"tags":["Connect"],"summary":"Write a customer's records into their connected systems","description":"Your records, in one of your schemas, written into each of the customer's connected systems you write that schema into (Settings → Morph Embedded → Connect), or only into connection_id. Each system gets its own write, checked like an import and written in the background, once: the write's import log and the records.written event say what was written and what the system refused. Up to 500 records per call.","operationId":"postTenantsByExternalIdWrites","parameters":[{"name":"external_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"schema":{"type":"string","pattern":"^[A-Za-z][A-Za-z0-9_]{0,63}$"},"records":{"minItems":1,"maxItems":500,"type":"array","items":{"type":"object","propertyNames":{"type":"string","maxLength":200},"additionalProperties":{}}},"connection_id":{"type":"string","minLength":1,"maxLength":100}},"required":["schema","records"]},"example":{"schema":"Customer","records":[{"name":"Brook Supplies Ltd","email":"accounts@brook.example"}]}}}},"responses":{"202":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"writes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"connection_id":{"type":"string"},"provider":{"type":"string"},"connector_id":{"type":"string"},"status":{"type":"string","enum":["writing","failed"]},"counts":{"type":"object","properties":{"received":{"type":"integer"},"valid":{"type":"integer"},"invalid":{"type":"integer"}},"required":["received","valid","invalid"]}},"required":["id","connection_id","provider","status","counts"]}}},"required":["writes"]}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/tenants/{external_id}/connections/{id}":{"delete":{"tags":["Connect"],"summary":"Remove a customer's connection","description":"Morph forgets the sign-in and stops its syncs. connection.disconnected is sent.","operationId":"deleteTenantsByExternalIdConnectionsById","parameters":[{"name":"external_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Done"},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/syncs/{id}/run":{"post":{"tags":["Connect"],"summary":"Run a sync now","description":"Brings what changed since the last run straight away, delivered like an import.","operationId":"postSyncsByIdRun","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"sync_id":{"type":"string"},"status":{"type":"string"}},"required":["sync_id","status"]}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/audit":{"get":{"tags":["Audit log"],"summary":"Who did what, and when","description":"Newest first: what your team changed in Settings, what your server did (by key), what your customers did in the importer and the Connect window, and what Morph did on its own. Ids, the names of settings that changed, and counts: never a value, a secret or a row. Kept 400 days; a customer's entries go when the customer is deleted. For the next page, send next_before as before.","operationId":"getAudit","parameters":[{"name":"tenant","in":"query","required":false,"description":"Only this customer's entries (your external_id for them).","schema":{"type":"string"}},{"name":"kind","in":"query","required":false,"description":"One kind (import.finished), or every kind of a group: embedded, settings, schema, key, link, inbox, sftp, import, mapping, customer, connection, sync.","schema":{"type":"string"}},{"name":"before","in":"query","required":false,"description":"Entries older than this: next_before from the page before, or a date-time.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Up to 200 (default 50).","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/AuditEntry"}},"has_more":{"type":"boolean"},"next_before":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["entries","has_more","next_before"]}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/schemas/{key}":{"put":{"tags":["Schemas"],"summary":"Create or change a target schema","description":"Saving a changed schema moves its version on by one; saving it unchanged does nothing.","operationId":"putSchemasByKey","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":100},"description":{"type":"string","maxLength":1000},"fields":{"minItems":1,"maxItems":300,"type":"array","items":{"type":"object","properties":{"name":{"type":"string","pattern":"^[A-Za-z_][A-Za-z0-9_.]{0,99}$"},"label":{"type":"string","minLength":1,"maxLength":100},"type":{"type":"string","enum":["string","number","integer","boolean","date","datetime","email","enum","json"]},"required":{"default":false,"type":"boolean"},"options":{"maxItems":500,"type":"array","items":{"type":"string","minLength":1,"maxLength":200}},"description":{"type":"string","maxLength":500},"unique":{"default":false,"type":"boolean"},"maxLength":{"type":"integer","minimum":1,"maximum":100000},"minLength":{"type":"integer","minimum":1,"maximum":100000},"min":{"type":"number"},"max":{"type":"number"},"earliest":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"latest":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"shapes":{"maxItems":10,"type":"array","items":{"type":"string","minLength":1,"maxLength":100}},"aliases":{"maxItems":30,"type":"array","items":{"type":"string","minLength":1,"maxLength":128}},"transforms":{"maxItems":10,"type":"array","items":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"trim"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"uppercase"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"lowercase"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"parse_number"},"decimal":{"default":".","type":"string","enum":[".",","]}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"parse_date"},"format":{"type":"string","enum":["YYYY-MM-DD","DD/MM/YYYY","MM/DD/YYYY","DD-MM-YYYY","DD.MM.YYYY","D MMM YYYY","MMM D, YYYY","YYYY/MM/DD","DD/MM/YY","MM/DD/YY"]}},"required":["kind","format"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"parse_boolean"},"true":{"maxItems":20,"type":"array","items":{"type":"string","maxLength":50}},"false":{"maxItems":20,"type":"array","items":{"type":"string","maxLength":50}}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"map_values"},"map":{"type":"object","propertyNames":{"type":"string","maxLength":200},"additionalProperties":{"type":"string","maxLength":200}}},"required":["kind","map"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"default"},"value":{"type":"string","maxLength":500}},"required":["kind","value"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"part"},"separator":{"default":" ","type":"string","minLength":1,"maxLength":10},"index":{"type":"integer","minimum":-5,"maximum":20},"rest":{"default":false,"type":"boolean"}},"required":["kind","index"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"replace"},"find":{"type":"string","minLength":1,"maxLength":100},"with":{"default":"","type":"string","maxLength":100}},"required":["kind","find"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"remove_characters"},"characters":{"type":"string","minLength":1,"maxLength":30}},"required":["kind","characters"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"titlecase"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"keep"},"what":{"type":"string","enum":["digits","letters","letters_and_digits"]}},"required":["kind","what"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"add_text"},"text":{"type":"string","minLength":1,"maxLength":50},"at":{"type":"string","enum":["start","end"]}},"required":["kind","text","at"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"add_column"},"column":{"type":"string","minLength":1,"maxLength":300},"separator":{"default":" ","type":"string","maxLength":10}},"required":["kind","column"],"additionalProperties":false}]}},"example":{"type":"string","maxLength":200}},"required":["name","type"],"additionalProperties":false}},"keyField":{"type":"string","pattern":"^[A-Za-z_][A-Za-z0-9_.]{0,99}$"},"documentLines":{"type":"boolean"}},"required":["label","fields"],"additionalProperties":false},"example":{"label":"Invoice","keyField":"invoice_number","fields":[{"name":"invoice_number","label":"Invoice number","type":"string","required":true,"unique":true,"aliases":["Inv No","Invoice #"]},{"name":"amount","label":"Amount","type":"number","required":true},{"name":"due_date","label":"Due date","type":"date","transforms":[{"kind":"parse_date","format":"DD/MM/YYYY"}]}]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"schema":{"$ref":"#/components/schemas/TargetSchema"},"changed":{"type":"boolean"}},"required":["schema","changed"]}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}},"get":{"tags":["Schemas"],"summary":"One target schema","operationId":"getSchemasByKey","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"schema":{"$ref":"#/components/schemas/TargetSchema"}},"required":["schema"]}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}},"delete":{"tags":["Schemas"],"summary":"Delete a target schema","operationId":"deleteSchemasByKey","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Done"},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/schemas":{"get":{"tags":["Schemas"],"summary":"List target schemas","operationId":"getSchemas","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"schemas":{"type":"array","items":{"$ref":"#/components/schemas/TargetSchema"}}},"required":["schemas"]}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/tenants":{"post":{"tags":["Customers"],"summary":"Add a customer (safe to repeat)","description":"Optional: POST /sessions and POST /jobs add the customer themselves.","operationId":"postTenants","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"external_id":{"type":"string","minLength":1,"maxLength":200},"name":{"type":"string","minLength":1,"maxLength":200}},"required":["external_id"]},"example":{"external_id":"cust_123","name":"Brook Supplies"}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}},"get":{"tags":["Customers"],"summary":"List customers","operationId":"getTenants","parameters":[{"name":"limit","in":"query","required":false,"description":"Up to 1000 (default 100).","schema":{"type":"string"}},{"name":"starting_after","in":"query","required":false,"description":"The last external_id of the page before.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"tenants":{"type":"array","items":{"type":"object","additionalProperties":true}},"has_more":{"type":"boolean"}},"required":["tenants","has_more"]}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/tenants/{external_id}":{"delete":{"tags":["Customers"],"summary":"Delete a customer and everything Morph holds for them","operationId":"deleteTenantsByExternalId","parameters":[{"name":"external_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Done"},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/profile":{"post":{"tags":["Headless mapping"],"summary":"Describe columns without keeping values","description":"Types, empty share, date formats and value shapes per column. No cell is returned or kept.","operationId":"postProfile","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"columns":{"minItems":1,"maxItems":500,"type":"array","items":{"type":"string","maxLength":300}},"rows":{"maxItems":5000,"type":"array","items":{"maxItems":500,"type":"array","items":{"anyOf":[{"type":"string","maxLength":32767},{"type":"number"},{"type":"boolean"},{"type":"null"}]}}}},"required":["columns","rows"]},"example":{"columns":["Inv No","Total","Due"],"rows":[["INV-1","1,200.50","31/03/2026"],["INV-2","88","01/04/2026"]]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"profiles":{"type":"array","items":{"type":"object","additionalProperties":true}}},"required":["profiles"]}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/mappings/suggest":{"post":{"tags":["Headless mapping"],"summary":"Suggest a mapping for a file's columns","operationId":"postMappingsSuggest","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tenant":{"type":"string","minLength":1,"maxLength":200},"target_schema":{"type":"string","pattern":"^[A-Za-z][A-Za-z0-9_]{0,63}$"},"columns":{"minItems":1,"maxItems":500,"type":"array","items":{"type":"string","maxLength":300}},"sample":{"maxItems":1000,"type":"array","items":{"maxItems":500,"type":"array","items":{"anyOf":[{"type":"string","maxLength":32767},{"type":"number"},{"type":"boolean"},{"type":"null"}]}}}},"required":["target_schema","columns"]},"example":{"tenant":"cust_123","target_schema":"Invoice","columns":["Inv No","Total","Due"],"sample":[["INV-1","1,200.50","31/03/2026"]]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"suggestions":{"type":"array","items":{"type":"object","additionalProperties":true}},"unmatched_required":{"type":"array","items":{"type":"string"}}},"required":["suggestions","unmatched_required"]}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/mappings":{"post":{"tags":["Headless mapping"],"summary":"Save a customer's confirmed mapping","description":"Files with the same columns from this customer then map themselves (POST /jobs without a mapping).","operationId":"postMappings","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tenant":{"type":"string","minLength":1,"maxLength":200},"target_schema":{"type":"string","pattern":"^[A-Za-z][A-Za-z0-9_]{0,63}$"},"columns":{"minItems":1,"maxItems":500,"type":"array","items":{"type":"string","maxLength":300}},"mapping":{"type":"object","propertyNames":{"type":"string","pattern":"^[A-Za-z_][A-Za-z0-9_.]{0,99}$"},"additionalProperties":{"type":"object","properties":{"column":{"type":"string","maxLength":300},"constant":{"type":"string","maxLength":500},"transforms":{"default":[],"maxItems":10,"type":"array","items":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"trim"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"uppercase"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"lowercase"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"parse_number"},"decimal":{"default":".","type":"string","enum":[".",","]}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"parse_date"},"format":{"type":"string","enum":["YYYY-MM-DD","DD/MM/YYYY","MM/DD/YYYY","DD-MM-YYYY","DD.MM.YYYY","D MMM YYYY","MMM D, YYYY","YYYY/MM/DD","DD/MM/YY","MM/DD/YY"]}},"required":["kind","format"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"parse_boolean"},"true":{"maxItems":20,"type":"array","items":{"type":"string","maxLength":50}},"false":{"maxItems":20,"type":"array","items":{"type":"string","maxLength":50}}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"map_values"},"map":{"type":"object","propertyNames":{"type":"string","maxLength":200},"additionalProperties":{"type":"string","maxLength":200}}},"required":["kind","map"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"default"},"value":{"type":"string","maxLength":500}},"required":["kind","value"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"part"},"separator":{"default":" ","type":"string","minLength":1,"maxLength":10},"index":{"type":"integer","minimum":-5,"maximum":20},"rest":{"default":false,"type":"boolean"}},"required":["kind","index"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"replace"},"find":{"type":"string","minLength":1,"maxLength":100},"with":{"default":"","type":"string","maxLength":100}},"required":["kind","find"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"remove_characters"},"characters":{"type":"string","minLength":1,"maxLength":30}},"required":["kind","characters"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"titlecase"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"keep"},"what":{"type":"string","enum":["digits","letters","letters_and_digits"]}},"required":["kind","what"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"add_text"},"text":{"type":"string","minLength":1,"maxLength":50},"at":{"type":"string","enum":["start","end"]}},"required":["kind","text","at"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"add_column"},"column":{"type":"string","minLength":1,"maxLength":300},"separator":{"default":" ","type":"string","maxLength":10}},"required":["kind","column"],"additionalProperties":false}]}}},"additionalProperties":false}}},"required":["tenant","target_schema","columns","mapping"]},"example":{"tenant":"cust_123","target_schema":"Invoice","columns":["Inv No","Total","Due"],"mapping":{"invoice_number":{"column":"Inv No"},"amount":{"column":"Total"},"due_date":{"column":"Due"}}}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"mapping_id":{"type":"string"}},"required":["mapping_id"]}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/mappings/{mapping_id}":{"get":{"tags":["Headless mapping"],"summary":"One saved mapping","operationId":"getMappingsByMappingId","parameters":[{"name":"mapping_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/validate":{"post":{"tags":["Headless mapping"],"summary":"Check records against a schema","operationId":"postValidate","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"target_schema":{"type":"string","pattern":"^[A-Za-z][A-Za-z0-9_]{0,63}$"},"records":{"maxItems":5000,"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}}},"required":["target_schema","records"]},"example":{"target_schema":"Invoice","records":[{"invoice_number":"INV-1","amount":1200.5}]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"valid":{"type":"integer"},"invalid":{"type":"integer"},"issues":{"type":"array","items":{"type":"object","properties":{"row":{"type":"integer"},"field":{"type":"string"},"code":{"type":"string","enum":["required","type","format","enum","unique","length","transform","vendor","range","shape"]},"message":{"type":"string"},"details":{"type":"object","description":"What message says, as data: expected (what the value should be), format (the date format it was read with), decimal (the decimal mark), max (the most characters), same_as_row (the row, numbered as row is, with the same value), unmapped (no column is mapped to the required field).","properties":{"expected":{"type":"string","enum":["number","integer","boolean","yes_no","json","text","single_value","email","date","datetime"]},"format":{"type":"string","enum":["YYYY-MM-DD","DD/MM/YYYY","MM/DD/YYYY","DD-MM-YYYY","DD.MM.YYYY","D MMM YYYY","MMM D, YYYY","YYYY/MM/DD","DD/MM/YY","MM/DD/YY"]},"decimal":{"type":"string","enum":[".",","]},"max":{"type":"integer"},"same_as_row":{"type":"integer"},"unmapped":{"type":"boolean"}}}},"required":["row","field","code","message"]}}},"required":["valid","invalid","issues"]}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}},"/transform":{"post":{"tags":["Headless mapping"],"summary":"Map, convert and check rows in one call","operationId":"postTransform","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"target_schema":{"type":"string","pattern":"^[A-Za-z][A-Za-z0-9_]{0,63}$"},"mapping_id":{"type":"string","minLength":1,"maxLength":100},"mapping":{"type":"object","propertyNames":{"type":"string","pattern":"^[A-Za-z_][A-Za-z0-9_.]{0,99}$"},"additionalProperties":{"type":"object","properties":{"column":{"type":"string","maxLength":300},"constant":{"type":"string","maxLength":500},"transforms":{"default":[],"maxItems":10,"type":"array","items":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"trim"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"uppercase"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"lowercase"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"parse_number"},"decimal":{"default":".","type":"string","enum":[".",","]}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"parse_date"},"format":{"type":"string","enum":["YYYY-MM-DD","DD/MM/YYYY","MM/DD/YYYY","DD-MM-YYYY","DD.MM.YYYY","D MMM YYYY","MMM D, YYYY","YYYY/MM/DD","DD/MM/YY","MM/DD/YY"]}},"required":["kind","format"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"parse_boolean"},"true":{"maxItems":20,"type":"array","items":{"type":"string","maxLength":50}},"false":{"maxItems":20,"type":"array","items":{"type":"string","maxLength":50}}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"map_values"},"map":{"type":"object","propertyNames":{"type":"string","maxLength":200},"additionalProperties":{"type":"string","maxLength":200}}},"required":["kind","map"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"default"},"value":{"type":"string","maxLength":500}},"required":["kind","value"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"part"},"separator":{"default":" ","type":"string","minLength":1,"maxLength":10},"index":{"type":"integer","minimum":-5,"maximum":20},"rest":{"default":false,"type":"boolean"}},"required":["kind","index"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"replace"},"find":{"type":"string","minLength":1,"maxLength":100},"with":{"default":"","type":"string","maxLength":100}},"required":["kind","find"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"remove_characters"},"characters":{"type":"string","minLength":1,"maxLength":30}},"required":["kind","characters"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"titlecase"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"keep"},"what":{"type":"string","enum":["digits","letters","letters_and_digits"]}},"required":["kind","what"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"add_text"},"text":{"type":"string","minLength":1,"maxLength":50},"at":{"type":"string","enum":["start","end"]}},"required":["kind","text","at"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"add_column"},"column":{"type":"string","minLength":1,"maxLength":300},"separator":{"default":" ","type":"string","maxLength":10}},"required":["kind","column"],"additionalProperties":false}]}}},"additionalProperties":false}},"columns":{"minItems":1,"maxItems":500,"type":"array","items":{"type":"string","maxLength":300}},"rows":{"maxItems":5000,"type":"array","items":{"maxItems":500,"type":"array","items":{"anyOf":[{"type":"string","maxLength":32767},{"type":"number"},{"type":"boolean"},{"type":"null"}]}}}},"required":["target_schema","columns","rows"]},"example":{"target_schema":"Invoice","columns":["Inv No","Total","Due"],"mapping":{"invoice_number":{"column":"Inv No"},"amount":{"column":"Total"},"due_date":{"column":"Due"}},"rows":[["INV-1","1,200.50","31/03/2026"]]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"records":{"type":"array","items":{"type":"object","additionalProperties":true}},"rejects":{"type":"array","items":{"type":"object","properties":{"row":{"type":"integer"},"issues":{"type":"array","items":{"type":"object","properties":{"row":{"type":"integer"},"field":{"type":"string"},"code":{"type":"string","enum":["required","type","format","enum","unique","length","transform","vendor","range","shape"]},"message":{"type":"string"},"details":{"type":"object","description":"What message says, as data: expected (what the value should be), format (the date format it was read with), decimal (the decimal mark), max (the most characters), same_as_row (the row, numbered as row is, with the same value), unmapped (no column is mapped to the required field).","properties":{"expected":{"type":"string","enum":["number","integer","boolean","yes_no","json","text","single_value","email","date","datetime"]},"format":{"type":"string","enum":["YYYY-MM-DD","DD/MM/YYYY","MM/DD/YYYY","DD-MM-YYYY","DD.MM.YYYY","D MMM YYYY","MMM D, YYYY","YYYY/MM/DD","DD/MM/YY","MM/DD/YY"]},"decimal":{"type":"string","enum":[".",","]},"max":{"type":"integer"},"same_as_row":{"type":"integer"},"unmapped":{"type":"boolean"}}}},"required":["row","field","code","message"]}}},"required":["row","issues"]}},"counts":{"type":"object","properties":{"received":{"type":"integer"},"valid":{"type":"integer"},"invalid":{"type":"integer"}},"required":["received","valid","invalid"]}},"required":["records","rejects","counts"]}}}},"400":{"description":"The request isn't valid; message says why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"401":{"description":"No server key, or a revoked one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}},"429":{"description":"Too many calls in a minute; wait for Retry-After.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]}}}}}}}},"webhooks":{"connection.connected":{"post":{"summary":"A customer connected a system (Connect)","description":"Its syncs start bringing records straight away. Signed with your signing secret: x-morph-signature is the hex HMAC-SHA256 of `${x-morph-timestamp}.${raw body}`. Refuse a request whose timestamp is older than your window (5 minutes is common).","parameters":[{"name":"x-morph-timestamp","in":"header","required":true,"schema":{"type":"string"}},{"name":"x-morph-signature","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string"},"connection":{"type":"object","properties":{"id":{"type":"string"},"provider":{"type":"string"},"account":{"anyOf":[{"type":"string"},{"type":"null"}]},"connector_id":{"type":"string"}},"required":["id","provider","account"]},"tenant":{"type":"object","properties":{"external_id":{"type":"string"}},"required":["external_id"]},"problem":{"type":"string"}},"required":["event","connection","tenant"]}}}},"responses":{"200":{"description":"Received"}}}},"connection.needs_reconnect":{"post":{"summary":"A customer's sign-in to their system stopped working","description":"Its syncs wait until the customer reconnects from the Connect window. Signed with your signing secret: x-morph-signature is the hex HMAC-SHA256 of `${x-morph-timestamp}.${raw body}`. Refuse a request whose timestamp is older than your window (5 minutes is common).","parameters":[{"name":"x-morph-timestamp","in":"header","required":true,"schema":{"type":"string"}},{"name":"x-morph-signature","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string"},"connection":{"type":"object","properties":{"id":{"type":"string"},"provider":{"type":"string"},"account":{"anyOf":[{"type":"string"},{"type":"null"}]},"connector_id":{"type":"string"}},"required":["id","provider","account"]},"tenant":{"type":"object","properties":{"external_id":{"type":"string"}},"required":["external_id"]},"problem":{"type":"string"}},"required":["event","connection","tenant"]}}}},"responses":{"200":{"description":"Received"}}}},"connection.disconnected":{"post":{"summary":"A customer's connection was removed","description":"By the customer, your team or your server. Signed with your signing secret: x-morph-signature is the hex HMAC-SHA256 of `${x-morph-timestamp}.${raw body}`. Refuse a request whose timestamp is older than your window (5 minutes is common).","parameters":[{"name":"x-morph-timestamp","in":"header","required":true,"schema":{"type":"string"}},{"name":"x-morph-signature","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string"},"connection":{"type":"object","properties":{"id":{"type":"string"},"provider":{"type":"string"},"account":{"anyOf":[{"type":"string"},{"type":"null"}]},"connector_id":{"type":"string"}},"required":["id","provider","account"]},"tenant":{"type":"object","properties":{"external_id":{"type":"string"}},"required":["external_id"]},"problem":{"type":"string"}},"required":["event","connection","tenant"]}}}},"responses":{"200":{"description":"Received"}}}},"records.written":{"post":{"summary":"A write into a customer's system finished (Connect)","description":"What one write did: how many records went in and how many the system refused, or why nothing was written. Never a value; the write's import log has the details. Signed with your signing secret: x-morph-signature is the hex HMAC-SHA256 of `${x-morph-timestamp}.${raw body}`. Refuse a request whose timestamp is older than your window (5 minutes is common).","parameters":[{"name":"x-morph-timestamp","in":"header","required":true,"schema":{"type":"string"}},{"name":"x-morph-signature","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string"},"write_id":{"type":"string"},"tenant":{"type":"object","properties":{"external_id":{"type":"string"}},"required":["external_id"]},"schema":{"type":"object","properties":{"key":{"type":"string"},"version":{"type":"integer"}},"required":["key","version"]},"connection":{"type":"object","properties":{"id":{"type":"string"},"provider":{"type":"string"},"connector_id":{"type":"string"}},"required":["id","provider"]},"status":{"type":"string","enum":["written","partly_written","failed"]},"counts":{"type":"object","properties":{"received":{"type":"integer"},"invalid":{"type":"integer"},"written":{"type":"integer"},"refused":{"type":"integer"}},"required":["received","invalid","written","refused"]},"problem":{"type":"string"}},"required":["event","write_id","tenant","schema","connection","status","counts"]}}}},"responses":{"200":{"description":"Received"}}}},"records.delivered":{"post":{"summary":"An import's records, in parts of up to 500","description":"Sent to your webhook address. Answer 2xx; Morph retries for 24 hours, then deletes the records. Signed with your signing secret: x-morph-signature is the hex HMAC-SHA256 of `${x-morph-timestamp}.${raw body}`. Refuse a request whose timestamp is older than your window (5 minutes is common).","parameters":[{"name":"x-morph-timestamp","in":"header","required":true,"schema":{"type":"string"}},{"name":"x-morph-signature","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"const":"records.delivered"},"batch_id":{"type":"string"},"tenant":{"type":"object","properties":{"external_id":{"type":"string"}},"required":["external_id"]},"schema":{"type":"object","properties":{"key":{"type":"string"},"version":{"type":"integer"}},"required":["key","version"]},"part":{"type":"integer"},"parts":{"type":"integer"},"records":{"type":"array","items":{"type":"object","additionalProperties":true}}},"required":["event","batch_id","tenant","schema","part","parts","records"]}}}},"responses":{"200":{"description":"Received"}}}},"import.completed":{"post":{"summary":"An import finished","description":"Sent once per import, after its records. delivery \"pull\" means they wait for GET /batches/{batch_id}. Signed with your signing secret: x-morph-signature is the hex HMAC-SHA256 of `${x-morph-timestamp}.${raw body}`. Refuse a request whose timestamp is older than your window (5 minutes is common).","parameters":[{"name":"x-morph-timestamp","in":"header","required":true,"schema":{"type":"string"}},{"name":"x-morph-signature","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"const":"import.completed"},"batch_id":{"type":"string"},"tenant":{"type":"object","properties":{"external_id":{"type":"string"}},"required":["external_id"]},"schema":{"type":"object","properties":{"key":{"type":"string"},"version":{"type":"integer"}},"required":["key","version"]},"counts":{"type":"object","properties":{"received":{"type":"integer"},"delivered":{"type":"integer"},"skipped":{"type":"integer"},"invalid":{"type":"integer"}},"required":["received","delivered","skipped","invalid"]},"user":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"]},"delivery":{"type":"string","enum":["webhook","pull"]}},"required":["event","batch_id","tenant","schema","counts","user"]}}}},"responses":{"200":{"description":"Received"}}}},"rows.check":{"post":{"summary":"Your own checks on rows, while the customer fixes their file","description":"Sent to your checks address (Settings → Morph Embedded → For developers), signed with the checks secret. Answer within 10 seconds with each row's problems; exists: true marks the row an update to a record you already have. Signed with your signing secret: x-morph-signature is the hex HMAC-SHA256 of `${x-morph-timestamp}.${raw body}`. Refuse a request whose timestamp is older than your window (5 minutes is common).","parameters":[{"name":"x-morph-timestamp","in":"header","required":true,"schema":{"type":"string"}},{"name":"x-morph-signature","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"const":"rows.check"},"tenant":{"type":"object","properties":{"external_id":{"type":"string"}},"required":["external_id"]},"schema":{"type":"object","properties":{"key":{"type":"string"},"version":{"type":"integer"}},"required":["key","version"]},"rows":{"type":"array","maxItems":500,"items":{"type":"object","properties":{"row":{"type":"integer"},"record":{"type":"object","additionalProperties":true}},"required":["row","record"]}}},"required":["event","tenant","schema","rows"]}}}},"responses":{"200":{"description":"Your answer","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array","items":{"type":"object","properties":{"row":{"type":"integer"},"errors":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["message"]}},"exists":{"type":"boolean"}},"required":["row"]}}},"required":["results"]}}}}}}}},"components":{"securitySchemes":{"serverKey":{"type":"http","scheme":"bearer","description":"A server key (morph_sk_…). Keep it on your server."}},"schemas":{"Job":{"type":"object","properties":{"job_id":{"type":"string"},"status":{"type":"string","enum":["queued","running","completed","failed","needs_mapping"]},"tenant":{"anyOf":[{"type":"string"},{"type":"null"}]},"target_schema":{"type":"string"},"filename":{"type":"string"},"sheet":{"anyOf":[{"type":"string"},{"type":"null"}]},"via":{"type":"string","enum":["api","email","sftp"],"description":"How the file came: from your server, or from the customer's email address or SFTP folder."},"batch_id":{"anyOf":[{"type":"string"},{"type":"null"}]},"mapping_source":{"anyOf":[{"type":"string"},{"type":"null"}]},"counts":{"type":"object","additionalProperties":true},"issues_summary":{"type":"array","items":{"type":"object","additionalProperties":true}},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"columns":{"type":"array","items":{"type":"string"}},"suggested_mapping":{"type":"object","additionalProperties":true},"questions":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"label":{"type":"string"},"kind":{"type":"string","enum":["unmatched_required","unsure"]}},"required":["field","kind"]}},"created_at":{"type":"string"},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"finished_at":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["job_id","status","target_schema","via","counts","created_at"]},"Inbox":{"type":"object","properties":{"id":{"type":"string"},"address":{"type":"string","description":"The address to send files to. Anyone holding it can send files for the customer."},"schema":{"type":"string"},"customer":{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name"]},"active":{"type":"boolean"},"received":{"type":"integer","description":"Files received."},"last_received_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"}},"required":["id","address","schema","customer","active","received","last_received_at","created_at"]},"SftpFolder":{"type":"object","properties":{"customer":{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name"]},"host":{"anyOf":[{"type":"string"},{"type":"null"}]},"port":{"type":"integer"},"username":{"type":"string"},"folders":{"type":"array","items":{"type":"string"},"description":"A folder per schema: /Invoice takes Invoice files."},"key_fingerprint":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The key they sign in with, as ssh-keygen -l prints it."},"status":{"type":"string","enum":["active","off"],"description":"off: Morph's SFTP server isn't running just now."},"received":{"type":"integer","description":"Files received."},"last_received_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"}},"required":["customer","host","port","username","folders","key_fingerprint","status","received","last_received_at","created_at"]},"ImportLog":{"type":"object","properties":{"id":{"type":"string"},"import_id":{"anyOf":[{"type":"string"},{"type":"null"}]},"sync_id":{"anyOf":[{"type":"string"},{"type":"null"}]},"via":{"type":"string","enum":["importer","website","link","team","api","sync","write","email","sftp"]},"title":{"type":"string"},"schema":{"type":"object","properties":{"key":{"type":"string"},"label":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["key","label"]},"status":{"type":"string","enum":["receiving","delivering","delivered","partly_delivered","waiting","failed","expired"]},"counts":{"type":"object","properties":{"received":{"type":"integer"},"valid":{"type":"integer"},"invalid":{"type":"integer"},"skipped":{"type":"integer"},"delivered":{"type":"integer"},"refused":{"type":"integer"}},"required":["received","valid","invalid","skipped","delivered","refused"]},"problems":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"},"count":{"type":"integer"},"rows":{"type":"array","items":{"type":"integer"}},"details":{"type":"object","description":"What message says, as data: expected (what the value should be), format (the date format it was read with), decimal (the decimal mark), max (the most characters), same_as_row (the row, numbered as row is, with the same value), unmapped (no column is mapped to the required field).","properties":{"expected":{"type":"string","enum":["number","integer","boolean","yes_no","json","text","single_value","email","date","datetime"]},"format":{"type":"string","enum":["YYYY-MM-DD","DD/MM/YYYY","MM/DD/YYYY","DD-MM-YYYY","DD.MM.YYYY","D MMM YYYY","MMM D, YYYY","YYYY/MM/DD","DD/MM/YY","MM/DD/YY"]},"decimal":{"type":"string","enum":[".",","]},"max":{"type":"integer"},"same_as_row":{"type":"integer"},"unmapped":{"type":"boolean"}}}},"required":["field","code","message","count","rows"]}},"refused":{"type":"array","items":{"type":"object","properties":{"record":{"type":"integer"},"message":{"type":"string"}},"required":["record","message"]}},"where":{"anyOf":[{"type":"string"},{"type":"null"}]},"place":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["app","server","google_sheet","google_drive","onedrive","sharepoint","sftp","system"]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["kind","name"]},{"type":"null"}]},"events":{"type":"array","items":{"type":"object","properties":{"at":{"type":"string"},"text":{"type":"string"},"code":{"type":"string","enum":["started","started_sync","started_write","written","write_failed","received","waiting","collected","delivered","retrying","expired_open","expired_undelivered","expired_uncollected","read_failed"]},"params":{"type":"object","additionalProperties":{"anyOf":[{"type":"string"},{"type":"number"}]}}},"required":["at","text"]}},"started_at":{"type":"string"},"finished_at":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","via","title","schema","status","counts","problems","refused","events","started_at"]},"AuditEntry":{"type":"object","properties":{"id":{"type":"string"},"at":{"type":"string","format":"date-time"},"kind":{"type":"string","enum":["embedded.enabled","embedded.disabled","settings.changed","schema.created","schema.updated","schema.deleted","key.created","key.revoked","link.created","link.disabled","inbox.created","inbox.disabled","sftp.created","sftp.removed","import.started","import.finished","mapping.saved","customer.deleted","connection.connected","connection.removed","connection.needs_reconnect","sync.run_requested","sync.mapping_confirmed"]},"tenant":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your external_id for the customer it is about; null for your own settings, keys and schemas."},"customer":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The customer's name (or external_id) as it is now."},"actor":{"oneOf":[{"type":"object","properties":{"type":{"const":"member"},"label":{"type":"string"},"user_id":{"type":"string"},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["type","label","user_id","email","name"]},{"type":"object","properties":{"type":{"const":"server"},"label":{"type":"string"},"key_id":{"anyOf":[{"type":"string"},{"type":"null"}]},"key_prefix":{"anyOf":[{"type":"string"},{"type":"null"}]},"key_label":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["type","label","key_id","key_prefix","key_label"]},{"type":"object","properties":{"type":{"const":"customer"},"label":{"type":"string"},"where":{"type":"string","enum":["importer","connect","inbox"]},"via":{"anyOf":[{"type":"string","enum":["app","website","link","email","sftp"]},{"type":"null"}]},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}]},"link_id":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["type","label","where","via","user_id","link_id"]},{"type":"object","properties":{"type":{"const":"morph"},"label":{"type":"string"}},"required":["type","label"]}],"description":"Who did it: someone on your team, your server (which key), a customer in the importer, the Connect window or by sending a file to their email address or SFTP folder (where inbox), or Morph itself. label is the plain words Settings shows."},"summary":{"type":"string","description":"What happened, in plain words."},"details":{"type":"object","properties":{"section":{"type":"string","enum":["use","website","branding","webhook","receive","alerts","checks","connect"]},"settings":{"type":"array","items":{"type":"string"},"description":"The names of the settings that changed, never their values."},"schema":{"type":"string"},"version":{"type":"integer"},"from":{"type":"string","enum":["helper_file"]},"key_id":{"type":"string"},"key_prefix":{"type":"string"},"link_id":{"type":"string"},"inbox_id":{"type":"string"},"sftp_key":{"type":"string","enum":["new","replaced"]},"days":{"type":"integer"},"import_id":{"type":"string"},"via":{"type":"string","enum":["importer","website","link","team","api","sync"]},"log_id":{"type":"string","description":"The import's log, for 30 days: GET /logs/{id}."},"customer":{"type":"string","description":"customer.deleted: your external_id for the customer deleted."},"connection_id":{"type":"string"},"provider":{"type":"string"},"connector_id":{"type":"string"},"sync_id":{"type":"string"},"object":{"type":"string"},"mapping_id":{"type":"string"}},"required":[],"additionalProperties":true},"counts":{"anyOf":[{"type":"object","additionalProperties":{"type":"integer"}},{"type":"null"}]}},"required":["id","at","kind","tenant","customer","actor","summary","details","counts"]},"TargetSchema":{"allOf":[{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":100},"description":{"type":"string","maxLength":1000},"fields":{"minItems":1,"maxItems":300,"type":"array","items":{"type":"object","properties":{"name":{"type":"string","pattern":"^[A-Za-z_][A-Za-z0-9_.]{0,99}$"},"label":{"type":"string","minLength":1,"maxLength":100},"type":{"type":"string","enum":["string","number","integer","boolean","date","datetime","email","enum","json"]},"required":{"default":false,"type":"boolean"},"options":{"maxItems":500,"type":"array","items":{"type":"string","minLength":1,"maxLength":200}},"description":{"type":"string","maxLength":500},"unique":{"default":false,"type":"boolean"},"maxLength":{"type":"integer","minimum":1,"maximum":100000},"minLength":{"type":"integer","minimum":1,"maximum":100000},"min":{"type":"number"},"max":{"type":"number"},"earliest":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"latest":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"shapes":{"maxItems":10,"type":"array","items":{"type":"string","minLength":1,"maxLength":100}},"aliases":{"maxItems":30,"type":"array","items":{"type":"string","minLength":1,"maxLength":128}},"transforms":{"maxItems":10,"type":"array","items":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"trim"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"uppercase"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"lowercase"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"parse_number"},"decimal":{"default":".","type":"string","enum":[".",","]}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"parse_date"},"format":{"type":"string","enum":["YYYY-MM-DD","DD/MM/YYYY","MM/DD/YYYY","DD-MM-YYYY","DD.MM.YYYY","D MMM YYYY","MMM D, YYYY","YYYY/MM/DD","DD/MM/YY","MM/DD/YY"]}},"required":["kind","format"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"parse_boolean"},"true":{"maxItems":20,"type":"array","items":{"type":"string","maxLength":50}},"false":{"maxItems":20,"type":"array","items":{"type":"string","maxLength":50}}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"map_values"},"map":{"type":"object","propertyNames":{"type":"string","maxLength":200},"additionalProperties":{"type":"string","maxLength":200}}},"required":["kind","map"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"default"},"value":{"type":"string","maxLength":500}},"required":["kind","value"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"part"},"separator":{"default":" ","type":"string","minLength":1,"maxLength":10},"index":{"type":"integer","minimum":-5,"maximum":20},"rest":{"default":false,"type":"boolean"}},"required":["kind","index"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"replace"},"find":{"type":"string","minLength":1,"maxLength":100},"with":{"default":"","type":"string","maxLength":100}},"required":["kind","find"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"remove_characters"},"characters":{"type":"string","minLength":1,"maxLength":30}},"required":["kind","characters"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"titlecase"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"keep"},"what":{"type":"string","enum":["digits","letters","letters_and_digits"]}},"required":["kind","what"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"add_text"},"text":{"type":"string","minLength":1,"maxLength":50},"at":{"type":"string","enum":["start","end"]}},"required":["kind","text","at"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"add_column"},"column":{"type":"string","minLength":1,"maxLength":300},"separator":{"default":" ","type":"string","maxLength":10}},"required":["kind","column"],"additionalProperties":false}]}},"example":{"type":"string","maxLength":200}},"required":["name","type"],"additionalProperties":false}},"keyField":{"type":"string","pattern":"^[A-Za-z_][A-Za-z0-9_.]{0,99}$"},"documentLines":{"type":"boolean"}},"required":["label","fields"],"additionalProperties":false},{"type":"object","properties":{"key":{"type":"string"},"version":{"type":"integer"},"updatedAt":{"type":"string","format":"date-time"}},"required":["key","version","updatedAt"]}]}}},"x-webhook-events":["records.delivered","import.completed","connector.requested","connection.connected","connection.needs_reconnect","connection.disconnected","records.written"]}