You can create a form using wbeditentity:
(new mw.Api()).postWithToken('csrf', { action:'wbeditentity', 'new': 'form', data: JSON.stringify({ lexemeId: 'L1', representations: { en: { language: 'en', value: 'test form' } }, grammaticalFeatures: [] }) })
However, the API response doesn’t contain the full entity data:
{ "entity": { "claims": {}, "id": null, "type": "form", "lastrevid": 1449 }, "success": 1 }
It doesn’t even contain the form ID, which would otherwise at least let you issue a wbgetentities request for the data. (You can try to work around this by getting the full entity data for the lexeme and assuming the last form is the one you added, but that’s susceptible to a race condition.)
(wbeditentity doesn’t yet support senses, but with some WIP patches to set up the wiring I’m seeing the same problem there, too.)
Current status: the form ID is now returned, and nothing else. That’s enough to get the form ID with a separate wbgetentities request, though.